Geshan's BlogA blog about software engineering, devops and web development2024-03-16T11:58:47Zhttps://geshan.com.np/Geshan Manandhargeshan@gmail.comHow to use Nginx with Docker Compose effectively with examples2024-03-16T11:58:47Zhttps://geshan.com.np/blog/2024/03/nginx-docker-compose/<p>Nginx, a free, open-source, high-performance web server and reverse proxy, has become a cornerstone of modern web applications. Its versatility, efficiency, and ability to handle high-traffic loads make it a popular choice among developers and organizations alike. In this post, you are going to learn how to use Niginx with Docker and Docker Compose with a simple example and another example that is closer to a real-life scenario, let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/nginx-docker-compose/01nginx-docker-compose.jpg" title="How to use Nginx with Docker Compose effectively with examples" alt="How to use Nginx with Docker Compose effectively with examples" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#nginx-and-docker-compose">Nginx and Docker compose</a></li>
<li><a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#prerequisites">Prerequisites</a></li>
<li><a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#nginx-docker-compose-a-simple-example">Nginx Docker Compose a simple example</a></li>
<li><a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#multi-container-example-with-nginx-and-docker-compose">Multi-container example with Nginx and Docker compose</a>
<ul>
<li><a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#the-components-of-nginx-docker-compose-a-multi-container-setup">The components of Nginx Docker compose a multi-container setup</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#conclusion">Conclusion</a></li>
</ul>
<h2 id="nginx-and-docker-compose" tabindex="-1">Nginx and Docker compose <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#nginx-and-docker-compose">#</a></h2>
<p>On top of being a great web server, Nginx has other useful features too like <a href="https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/">load balancing</a>, <a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/%E2%80%8B%E2%80%8Bhttps://docs.nginx.com/nginx/admin-guide/content-cache/content-caching/">content caching</a>, and <a href="https://docs.nginx.com/nginx/admin-guide/mail-proxy/mail-proxy/">mail proxy</a>. You can even set up <a href="https://github.com/kjdev/nginx-auth-jwt">JWT authentication</a> with Nginx. That speaks volumes about how versatile Nginx is.</p>
<p>In the realm of containerization, Docker has become the de facto standard for packaging and deploying applications. Docker Compose, a companion tool, simplifies the management of multi-container applications by allowing you to define and run them using a single YAML file.</p>
<p>When you combine Nginx with Docker Compose, you unlock a powerful and efficient way to deploy and manage web applications. Docker Compose streamlines the process of running multiple containers, including your Nginx web server and any backend services your application might rely on. You could potentially run multiple backend servers and route the traffic to them using Nginx in front of them as a <a href="https://www.cloudflare.com/en-gb/learning/cdn/glossary/reverse-proxy/">reverse proxy</a>.</p>
<p>In the next section, you will look at a simple example with Nginx and Docker compose to host a small brochure website with static files.</p>
<h3 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#prerequisites">#</a></h3>
<p>Before you embark on this journey, let's ensure you have the following prerequisites:</p>
<ol>
<li>
<p>A basic understanding of Docker and Docker Compose: Familiarity with Docker commands like <code>docker build</code>, <code>docker run</code>, and <code>docker-compose up</code> is essential. If you're new to Docker, I recommend checking out the official Docker documentation or online tutorials to get up to speed. Also, you will need Docker running on your machine, the examples are based on Docker version 24.0.2 and Docker compose version 2.18.1.</p>
</li>
<li>
<p>General understanding of Nginx: Knowing how Nginx works and how it is configured will be greatly helpful.</p>
</li>
<li>
<p>Node.js and NPM installed: We'll be using a simple Node.js application as an example, so having Node.js and NPM (Node Package Manager) installed on your system is useful.</p>
</li>
<li>
<p>Text editor or IDE: You'll need a text editor or IDE to create and edit the Dockerfile and docker-compose.yml files. I will be using VSCode.</p>
</li>
</ol>
<p>In the next, section you will run a simple example to serve static files with Nginx and Docker Compose.</p>
<h2 id="nginx-docker-compose-a-simple-example" tabindex="-1">Nginx Docker Compose a simple example <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#nginx-docker-compose-a-simple-example">#</a></h2>
<p>Let's begin with a straightforward example that illustrates how to use Nginx with Docker Compose to host static files. For this example, you want to create a brochure website for your imaginary Gen AI startup named Summrzer (a different variation for Summarizer). Your design skills could be better, so you get a responsive theme from <a href="http://html5up.net/">HTML5up.net</a> called <a href="https://html5up.net/stellar">Steller</a>.</p>
<p>To get started you will first clone the ready-made repository where the files have been edited to look like a landing page of our imaginary start-up <code>Summrzer</code>. You can clone the repository with the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone git@github.com:geshan/nginx-docker-compose.git</code></pre>
<p>After that, you have to run the docker compose command pointing it to the <code>basic.yaml</code> file with the <code>up</code> parameter. Let’s look at that file first:</p>
<pre class="language-bash"><code class="language-bash">version: <span class="token string">'3.8'</span><br />services:<br /> nginx:<br /> image: nginx:1-alpine<br /> ports:<br /> - <span class="token number">8089</span>:80<br /> volumes:<br /> - ./html5up-stellar/:/usr/share/nginx/html</code></pre>
<p>Let's break down this Docker compose file:</p>
<ul>
<li><strong>version:</strong> Specifies the Docker Compose file format version, in this case, 3.8.</li>
<li><em>services:</em>* Defines the services that make up our application. In this case, it is only Nginx.</li>
<li><em>image:</em>* Uses the <code>nginx:1-alpoine</code> image from Docker Hub. Which is the smaller Alpine version, not the default Debian one.</li>
<li><strong>ports:</strong> Maps the host's port 8089 to the container's port 80, allowing access to the web server running in the container from the host machine with <code>http://localhost:8089</code></li>
<li><strong>volumes:</strong> You have mounted the local <code>./html5up-stellar</code> to <code>/usr/share/nginx/html</code> default document root fo Nignx.</li>
</ul>
<p>This could have also been done with a Dockerfile but it is easier with this configuration and much easier to build as well as change any configuration.</p>
<p>Now, to run the simple version of the Nginx with the above Docker Compose config, you can execute the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> compose <span class="token parameter variable">-f</span> basic.yaml up</code></pre>
<p>It will show the following output on the command line:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nginx-docker-compose/02nginx-docker-compose-simple.jpg" title="Running a simple Nginx Docker compose example with single container" alt="Running a simple Nginx Docker compose example with single container" />
<p>To check the running app, open your favorite browser and point the tab to <code>http://localhost:8089</code>, you will see something like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nginx-docker-compose/03summrzer.jpg" title="Summarizer static site running a simple Nginx Docker compose example with single container" alt="Summarizer static site running a simple Nginx Docker compose example with single container" />
<p>Hurray! You have run a simple version of Nginx that can serve static files like HTML, JavaScirpt, CSS, and images. You can add more things to the configuration like <a href="https://webdock.io/en/docs/webdock-control-panel/optimizing-performance/setting-cache-control-headers-common-content-types-nginx-and-apache">Cache-Control headers with Nginx</a>, that can be a topic for another blog post.</p>
<p>You can stop the command by pressing <code>Ctrl+C</code>. In the next part, you will learn how to run multiple containers with Nginx using a Docker compose configuration file.</p>
<h2 id="multi-container-example-with-nginx-and-docker-compose" tabindex="-1">Multi-container example with Nginx and Docker compose <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#multi-container-example-with-nginx-and-docker-compose">#</a></h2>
<p>Now that you've seen a basic example, let's move on to a multi-container scenario. You will create a setup where Nginx serves static files for the root path <code>/</code> and acts as a reverse proxy for a Node.js API running on a different container for the <code>/api</code> path. To do this, the Docker compose file is already in the cloned repository at <code>./compose.yaml</code>, which looks like the below:</p>
<pre class="language-bash"><code class="language-bash">version: <span class="token string">"3.8"</span><br />services:<br /> node:<br /> build:<br /> context: ./api<br /> target: dev<br /> volumes:<br /> - ./api/index.js:/src/index.js<br /> nginx:<br /> restart: always<br /> image: nginx:1-alpine<br /> ports:<br /> - <span class="token number">8089</span>:80<br /> volumes:<br /> - ./html5up-stellar/:/var/www/html<br /> - ./nginx/default.conf:/etc/nginx/conf.d/default.conf<br /> depends_on:<br /> - <span class="token function">node</span></code></pre>
<p>The file looks similar to the above one, still, let’s discuss the newly added things:</p>
<ul>
<li><strong>Services</strong>: In this configuration, there are two services <code>node</code> which runs a simple Node.js app, and Nginx which sits in front of the Node.js app as a reverse proxy. Nginx will forward all requests to the <code>/api</code> path to the Node.js app. The Node.js app is in the <code>../api</code> folder and has its own <a href="https://github.com/geshan/nginx-docker-compose/blob/master/api/Dockerfile">Dockerfile</a>. You can learn more about <a href="https://geshan.com.np/blog/2020/11/nodejs-with-docker/">Node.js with Docker</a> too.</li>
<li><strong>Nginx Volumes:</strong> There are two volumes this time, first one is similar to the above. The second one the key to this configuration which holds the definition of what the <code>/</code> and <code>/api</code> paths should do. You will know about this later.</li>
<li><strong>Depends on</strong>: Here it says that the Nginx service will be started after the Node.js service with depends on. You can read more about <a href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/blog/2024/02/docker-compose-depends-on/">Docker compose depends on</a> and learn about it.</li>
</ul>
<p>Next, you will learn about the components of this two-container setup.</p>
<h3 id="the-components-of-nginx-docker-compose-a-multi-container-setup" tabindex="-1">The components of Nginx Docker compose a multi-container setup <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#the-components-of-nginx-docker-compose-a-multi-container-setup">#</a></h3>
<p>As discussed, there is a Node.js app that is a simple API with a single file that looks like the below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> port <span class="token operator">=</span> <span class="token number">8181</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'alive'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/summary'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token string">'https://en.wikipedia.org/wiki/HTTP'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">summary</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">HTTP, or Hypertext Transfer Protocol, is an application layer protocol used in the World Wide Web to facilitate data communication. It's the foundation for exchanging information between web browsers and servers. The protocol's functions include requests, responses, methods, and headers. HTTP has evolved over time, with versions 1.0, 1.1, 2, and 3 currently in use. HTTPS, a secure version of HTTP, is widely used for increased security. HTTP is a fundamental protocol in web communication, providing a structured method for data transfer and enabling the functionality of the internet.</span><span class="token template-punctuation string">`</span></span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Example app listening on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>It is a basic Express.js app that sends back a stock response which adds like a demo to the <code>Summrzer</code> start-up story.</p>
<p>A docker file has been added to serve this Node.js app that looks like the below:</p>
<pre class="language-bash"><code class="language-bash">FROM node:20-alpine as base<br /><br />WORKDIR /src<br />COPY package.json package-lock.json /src/<br />EXPOSE <span class="token number">8181</span><br /><br />FROM base as production<br />ENV <span class="token assign-left variable">NODE_ENV</span><span class="token operator">=</span>production<br />RUN <span class="token function">npm</span> ci<br />COPY <span class="token builtin class-name">.</span> /src<br />CMD <span class="token punctuation">[</span><span class="token string">"node"</span>, <span class="token string">"index.js"</span><span class="token punctuation">]</span><br /><br />FROM base as dev<br />ENV <span class="token assign-left variable">NODE_ENV</span><span class="token operator">=</span>development<br />RUN <span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> nodemon <span class="token operator">&&</span> <span class="token function">npm</span> <span class="token function">install</span><br />COPY <span class="token builtin class-name">.</span> /src<br />CMD <span class="token punctuation">[</span><span class="token string">"nodemon"</span>, <span class="token string">"index.js"</span><span class="token punctuation">]</span></code></pre>
<p>The other component is the Nginx container, which has a configuration loaded to it in addition to the static files. The Nginx configuration placed in <code>./nginx/default.conf</code> looks as follows:</p>
<pre class="language-bash"><code class="language-bash">server <span class="token punctuation">{</span><br /> location / <span class="token punctuation">{</span><br /> root /var/www/html<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> location /api/ <span class="token punctuation">{</span><br /> proxy_set_header Host <span class="token variable">$host</span><span class="token punctuation">;</span><br /> proxy_set_header X-Real-IP <span class="token variable">$remote_addr</span><span class="token punctuation">;</span><br /> proxy_set_header X-Forwarded-For <span class="token variable">$proxy_add_x_forwarded_for</span><span class="token punctuation">;</span><br /> proxy_set_header X-Forwarded-Proto <span class="token variable">$scheme</span><span class="token punctuation">;</span><br /><br /> proxy_pass http://node:8181/<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>It is a simple configuration that says, if the user hits the <code>/</code> path serve the static files from <code>/var/www/html</code> this is where the <code>hmll5up-stellar</code> files are mounted in the Docker compose file. It can be made better with extra configs like cache headers which is out of the scope of this tutorial.</p>
<p>The second block is the interesting one, where requests to <code>/api/</code> will be routed to <code>localhost:8181</code> this is where the Node.js express app is running. This app is not accessible from the host machine as no ports are exposed for the <code>node</code> service in the above Docker compose file. It also sets additional proxy headers to ensure proper communication between Nginx and the Node.js application. It sends the Real IP to the node service, and the <a href="https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/">X-Forwarded-For</a> header is used to standardize sending the original IP. The <code>X-Forwarded-Proto</code> <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto">header</a> essentially identifies HTTP/HTTPS traffic.</p>
<p>Proxy pass is saying to forward all requests to <code>/api</code> to the Node.js service running on port 8181.<br />
To run this two container setup, you can execute the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> compose up</code></pre>
<p>You will see an output like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nginx-docker-compose/04nginx-docker-compose-multi.jpg" title="Running a complex Nginx Docker compose example with two containers" alt="Running a complex Nginx Docker compose example with two containers" />
<p>If you go to <code>http://localhost:8089</code> you will see a similar output of the modified stellar template as you did in the previous section. To check that the Node.js API is running properly you can go to <code>http://localhost:8089/ap/summaryi</code> on your favorite browser, it will yield something like:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nginx-docker-compose/05summrzer-api.jpg" title="Summarzer API running with Nginx and Docker compose with reverse proxy to a Node.js app" alt="Summarzer API running with Nginx and Docker compose with reverse proxy to a Node.js app" />
<p>There you have it, you have successfully run two examples with Nginx and Docker compose. The first one with Nginx only serves static files and the second one with Nginx serves both static files and acts as a reverse proxy for a simple Node.js app.</p>
<h3 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2024/03/nginx-docker-compose/#conclusion">#</a></h3>
<p>Using Nginx with Docker Compose provides a powerful and efficient way to deploy and manage web applications. Docker Compose simplifies the process of running multiple containers, including your Nginx web server and any backend services your application might rely on. This combination offers advantages such as simplified configuration portability, scalability, and isolation.</p>
<p>Through the two examples presented in this post, you've learned how to use Nginx with Docker Compose to host static files and act as a reverse proxy for a Node.js API. These examples demonstrate the basic principles of using Nginx with Docker Compose, and you can build upon them to create more complex and sophisticated deployments with extra features like Caching and Load balancing.</p>
<p>By leveraging the power of Nginx and Docker Compose, you can streamline your web development workflow and deploy and manage your applications with ease and efficiency.</p>
How to use docker compose depends_on a beginner's guide2024-02-27T11:58:47Zhttps://geshan.com.np/blog/2024/02/docker-compose-depends-on/<p>Docker Compose is a powerful tool that allows you to define and run multi-container Docker applications. It simplifies the process of managing and orchestrating multiple containers, making it a popular choice for development and testing environments. One of the key features of Docker Compose is the <code>depends_on</code> option, which allows you to specify dependencies between services. In this beginner's guide, you will explore how to use <code>depends_on</code> effectively, ensuring your services start up in the correct order and function seamlessly. Let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/docker-compose-depends-on/01docker-compose-depends-on.jpg" title="How to use docker compose depends_on a beginner's guide" alt="How to use docker compose depends_on a beginner's guide" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#docker-compose-depends-on">Docker compose depends on</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#difference-between-depends_on-and-links">Difference between depends_on and links</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#docker-compose-depends-on-under-the-covers">Docker compose depends on under the covers</a>
<ul>
<li><a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#services-startup-condition-with-service_healthy">Services startup condition with service_healthy</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#example-with-depends_on-and-service_healthy-condition">Example with depends_on and service_healthy condition</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#conclusion">Conclusion</a></li>
</ul>
<h2 id="docker-compose-depends-on" tabindex="-1">Docker compose depends on <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#docker-compose-depends-on">#</a></h2>
<p>Before we dive into <code>depends_on</code>, let's briefly recap Docker and Docker Compose. <a href="https://docs.docker.com/get-started/overview/">Docker</a> is a containerization technology that packages and runs applications in isolated environments called containers. <a href="https://docs.docker.com/compose/">Docker Compose</a> builds upon Docker, enabling you to define and manage multiple containers and their configurations in a single YAML file called <code>docker-compose.yml</code>. This declarative approach streamlines the process of running and orchestrating complex applications. You get free from long <code>docker run</code> commands using this declarative and easy-to-understand syntax that can be comprehended in a single glance.</p>
<p>Now, where does <code>depends_on</code> fit into this picture? When working with multi-container applications, it's often crucial to ensure that services start up in a specific order or that the dependent service starts and is ready before the main service.</p>
<p>For example, if your application depends on a database, the database service needs to be running before your application service starts. This is where <code>depends_on</code> comes in. It allows you to specify which services a particular service depends on, ensuring that the dependent services are started before the service that relies on them.</p>
<h2 id="difference-between-depends_on-and-links" tabindex="-1">Difference between depends_on and links <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#difference-between-depends_on-and-links">#</a></h2>
<p>It's important to distinguish <code>depends_on</code> from <code>links</code>. While <code>links</code> create network aliases and allow containers to communicate with each other by their service names, <code>depends_on</code> solely focuses on startup order. It does not automatically guarantee that the dependent service is ready to accept connections or requests. You will explore how to handle readiness checks later in this guide.</p>
<p>Let’s look at an example for an application that is a Node.js API (for Quotes) that uses Docker and has a Postgres database to store the data. The full <a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/blog/2021/01/nodejs-postgresql-tutorial/">Node.js Postgres</a> tutorial is available if you want to learn and understand how it is built. A working docker compose file with both the Node.js API and Postgres database services using <code>links</code> to make it possible for the Node.js container to talk to the db can look like the below:</p>
<pre class="language-yaml"><code class="language-yaml"><span class="highlight-line"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3.8'</span></span><br /><span class="highlight-line"><span class="token key atrule">services</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">db</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">image</span><span class="token punctuation">:</span> postgres<span class="token punctuation">:</span>14.1<span class="token punctuation">-</span>alpine</span><br /><span class="highlight-line"> <span class="token key atrule">restart</span><span class="token punctuation">:</span> always </span><br /><span class="highlight-line"> <span class="token key atrule">environment</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> POSTGRES_USER=postgres</span><br /><span class="highlight-line"> <span class="token punctuation">-</span> POSTGRES_PASSWORD=postgres</span><br /><span class="highlight-line"> <span class="token key atrule">ports</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> <span class="token string">'5432:5432'</span></span><br /><span class="highlight-line"> <span class="token key atrule">volumes</span><span class="token punctuation">:</span> </span><br /><span class="highlight-line"> <span class="token punctuation">-</span> db<span class="token punctuation">:</span>/var/lib/postgresql/data</span><br /><span class="highlight-line"> <span class="token punctuation">-</span> ./db/init.sql<span class="token punctuation">:</span>/docker<span class="token punctuation">-</span>entrypoint<span class="token punctuation">-</span>initdb.d/create_tables.sql</span><br /><span class="highlight-line"> <span class="token key atrule">api</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">container_name</span><span class="token punctuation">:</span> quotes<span class="token punctuation">-</span>api</span><br /><span class="highlight-line"> <span class="token key atrule">build</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">context</span><span class="token punctuation">:</span> ./</span><br /><span class="highlight-line"> <span class="token key atrule">target</span><span class="token punctuation">:</span> production</span><br /><span class="highlight-line"> <span class="token key atrule">image</span><span class="token punctuation">:</span> quotes<span class="token punctuation">-</span>api</span><br /><span class="highlight-line"> <span class="token key atrule">restart</span><span class="token punctuation">:</span> always</span><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">links</span><span class="token punctuation">:</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token punctuation">-</span> db </mark><br /><span class="highlight-line"> <span class="token key atrule">ports</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> 3000<span class="token punctuation">:</span><span class="token number">3000</span></span><br /><span class="highlight-line"> <span class="token key atrule">environment</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">NODE_ENV</span><span class="token punctuation">:</span> production</span><br /><span class="highlight-line"> <span class="token key atrule">DB_HOST</span><span class="token punctuation">:</span> db</span><br /><span class="highlight-line"> <span class="token key atrule">DB_PORT</span><span class="token punctuation">:</span> <span class="token number">5432</span></span><br /><span class="highlight-line"> <span class="token key atrule">DB_USER</span><span class="token punctuation">:</span> postgres</span><br /><span class="highlight-line"> <span class="token key atrule">DB_PASSWORD</span><span class="token punctuation">:</span> postgres</span><br /><span class="highlight-line"> <span class="token key atrule">DB_NAME</span><span class="token punctuation">:</span> postgres</span><br /><span class="highlight-line"> <span class="token key atrule">volumes</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> ./<span class="token punctuation">:</span>/src</span><br /><span class="highlight-line"> <span class="token punctuation">-</span> /src/node_modules</span><br /><span class="highlight-line"><span class="token key atrule">volumes</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">db</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">driver</span><span class="token punctuation">:</span> local</span></code></pre>
<p>You can understand more about a similar docker compose file for <a href="https://geshan.com.np/blog/2021/12/docker-postgres/#postgresql-with-docker-compose">Docker and Postgres</a>. The above example defines is using docker compose file version <code>3.8</code>. You have defined two services in this <code>docker-compose.yml</code> file. The first is the <code>db</code> and the second one is the <code>api</code>. You can find see the <a href="https://github.com/geshan/nodejs-posgresql/blob/master/Dockerfile">Dockerfile</a> used for the <code>api</code> too. The <code>db</code> service uses the official Postgres version <code>14.1</code> with the <code>alpine</code> flavor as it is a small image and ultimately a smaller container. It uses some environment variables and volumes, you can read about it more on <a href="https://github.com/geshan/nodejs-posgresql/blob/master/Dockerfile">Postgres with docker compose</a>.</p>
<p>Next, the API container is defined that uses a local Dockerfile built with the <code>production</code> context. It also has some needed environment variables defined and runs on port <code>3000</code>. It also has volumes so that the data is persisted across container restarts. The main part here is <code>links</code> (highlighted in yellow in the above code snippte) says that the API links to the <code>db</code> and can communicate with it.</p>
<p>If you start both services with <code>docker compose up</code> it will give a log like the one below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/docker-compose-depends-on/02docker-compose-depends-on-links.jpg" title="With Docker compose links you cannot specify the startup sequence of the services/containers" alt="With Docker compose links you cannot specify the startup sequence of the services/containers" />
<p>Notice that before the DB has fully started the API has started, this will be similar even if <code>depends_on</code> is used without a condition.</p>
<p>In the next section, you will learn about the depends on and service_healthy condition.</p>
<h2 id="docker-compose-depends-on-under-the-covers" tabindex="-1">Docker compose depends on under the covers <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#docker-compose-depends-on-under-the-covers">#</a></h2>
<p>Docker compose <code>depends_on</code> only <a href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/%E2%80%8B%E2%80%8Bhttps://docs.docker.com/compose/startup-order/">specifies the order</a> in which the services should start when no conditions are used. While <code>depends_on</code> ensures that services start in the correct order, it's important to understand that it does not guarantee that the dependent service is ready to accept connections or requests.</p>
<p>To address this, you can use additional tools or techniques to check the readiness of the dependent service. One common approach is to use a health check script or tool that verifies the service's availability before proceeding. For example, you could use a script that checks if the PostgreSQL database is listening on port 5432 before starting your Node.js application. <a href="https://github.com/vishnubob/wait-for-it">Wait for it</a> is a tool you can reach but it is not the docker compose native way of waiting for the dependent service to be ready.</p>
<p>So what is the native docker compose <code>depends_on</code> way to do it, you will know about it next.</p>
<h3 id="services-startup-condition-with-service_healthy" tabindex="-1">Services startup condition with service_healthy <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#services-startup-condition-with-service_healthy">#</a></h3>
<p>Docker Compose added a new <a href="https://docs.docker.com/compose/startup-order/#control-startup">condition</a> called <code>service_started</code> and <code>service_healthy</code> conditions. The <code>service_healthy</code> condition allows you to specify that a service should only start after another service has successfully started with a health check. This provides a more fine-grained level of control in conjunction with <code>depends_on</code>.</p>
<p>With <code>service_healthy</code>, you can specify a condition that checks the health of the dependent service. For example, you can specify that a service should only start after the dependent service has started and is listening on a specific port. This ensures that the dependent service is ready to accept connections before the service that depends on it starts.</p>
<p>You can use just depends_on with docker compose but it will only make sure that the dependent services start before the one that depends on it. To make sure that the dependent service has started and is ready/healthy to start accepting requests/connections use <code>depends_on</code> with a health check on the dependent service. You can have a look at an example in the next section.</p>
<h2 id="example-with-depends_on-and-service_healthy-condition" tabindex="-1">Example with depends_on and service_healthy condition <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#example-with-depends_on-and-service_healthy-condition">#</a></h2>
<p>Let's consider a practical example to illustrate how to use <code>depends_on</code> with the <code>service_healthy</code> condition. You will use the same Node.js API that connects to a PostgreSQL database to fetch quotes. You want to ensure that the PostgreSQL database starts and can accept connections before your Node.js application starts.</p>
<p>Here's how you can achieve this with a docker-compose.yml file:</p>
<pre class="language-yaml"><code class="language-yaml"><span class="highlight-line"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3.8'</span></span><br /><span class="highlight-line"><span class="token key atrule">services</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">db</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">image</span><span class="token punctuation">:</span> postgres<span class="token punctuation">:</span>14.1<span class="token punctuation">-</span>alpine</span><br /><span class="highlight-line"> <span class="token key atrule">restart</span><span class="token punctuation">:</span> always</span><br /><span class="highlight-line"> <span class="token key atrule">healthcheck</span><span class="token punctuation">:</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">test</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"CMD-SHELL"</span><span class="token punctuation">,</span> <span class="token string">"pg_isready -U postgres"</span><span class="token punctuation">]</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">interval</span><span class="token punctuation">:</span> 5s</mark><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">timeout</span><span class="token punctuation">:</span> 5s</mark><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">retries</span><span class="token punctuation">:</span> <span class="token number">5</span></mark><br /><span class="highlight-line"> <span class="token key atrule">environment</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> POSTGRES_USER=postgres</span><br /><span class="highlight-line"> <span class="token punctuation">-</span> POSTGRES_PASSWORD=postgres</span><br /><span class="highlight-line"> <span class="token key atrule">ports</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> <span class="token string">'5432:5432'</span></span><br /><span class="highlight-line"> <span class="token key atrule">volumes</span><span class="token punctuation">:</span> </span><br /><span class="highlight-line"> <span class="token punctuation">-</span> db<span class="token punctuation">:</span>/var/lib/postgresql/data</span><br /><span class="highlight-line"> <span class="token punctuation">-</span> ./db/init.sql<span class="token punctuation">:</span>/docker<span class="token punctuation">-</span>entrypoint<span class="token punctuation">-</span>initdb.d/create_tables.sql</span><br /><span class="highlight-line"> <span class="token key atrule">api</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">container_name</span><span class="token punctuation">:</span> quotes<span class="token punctuation">-</span>api</span><br /><span class="highlight-line"> <span class="token key atrule">build</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">context</span><span class="token punctuation">:</span> ./</span><br /><span class="highlight-line"> <span class="token key atrule">target</span><span class="token punctuation">:</span> production</span><br /><span class="highlight-line"> <span class="token key atrule">image</span><span class="token punctuation">:</span> quotes<span class="token punctuation">-</span>api</span><br /><span class="highlight-line"> <span class="token key atrule">restart</span><span class="token punctuation">:</span> always</span><br /><span class="highlight-line"> <span class="token key atrule">depends_on</span><span class="token punctuation">:</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">db</span><span class="token punctuation">:</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token key atrule">condition</span><span class="token punctuation">:</span> service_healthy</mark><br /><span class="highlight-line"> <span class="token key atrule">ports</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> 3000<span class="token punctuation">:</span><span class="token number">3000</span></span><br /><span class="highlight-line"> <span class="token key atrule">environment</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">NODE_ENV</span><span class="token punctuation">:</span> production</span><br /><span class="highlight-line"> <span class="token key atrule">DB_HOST</span><span class="token punctuation">:</span> db</span><br /><span class="highlight-line"> <span class="token key atrule">DB_PORT</span><span class="token punctuation">:</span> <span class="token number">5432</span></span><br /><span class="highlight-line"> <span class="token key atrule">DB_USER</span><span class="token punctuation">:</span> postgres</span><br /><span class="highlight-line"> <span class="token key atrule">DB_PASSWORD</span><span class="token punctuation">:</span> postgres</span><br /><span class="highlight-line"> <span class="token key atrule">DB_NAME</span><span class="token punctuation">:</span> postgres</span><br /><span class="highlight-line"> <span class="token key atrule">volumes</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token punctuation">-</span> ./<span class="token punctuation">:</span>/src</span><br /><span class="highlight-line"> <span class="token punctuation">-</span> /src/node_modules</span><br /><span class="highlight-line"><span class="token key atrule">volumes</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">db</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> <span class="token key atrule">driver</span><span class="token punctuation">:</span> local</span></code></pre>
<p>In this example as the above one, you have two services: <code>db</code> and <code>api</code>. The <code>db</code> service uses the official PostgreSQL 14.1 Alpine image and exposes port 5432. It also defines environment variables for the database user, password, and database name. The <code>api</code> service represents your Node.js application, which depends on the <code>db</code> service. This dependency is specified using the <code>depends_on</code> option.</p>
<p>The Node.js app specifies that it <code>depends on</code> the db service. The additional condition on the depends on you have specified is the dependent service has to be healthy with <code>service_healthy</code>. It has been highlighted in yellow in the above code. This makes sure that the <code>api</code> services starts only after the <code>db</code> service is healthy (able to receive connections).</p>
<p>On the <code>db</code> service a <a href="https://docs.docker.com/compose/compose-file/05-services/#healthcheck">healthcheck</a> is defined that uses the <a href="https://www.postgresql.org/docs/current/app-pg-isready.html">pg_isready</a> tool. There are some options for the health check, first one is the test for the health check. To check if the DB is healthy you are using the <code>pg_isready</code> tool that checks the connection status of a PostgreSQL server, the exit status for this command determines the status.</p>
<p>There are other options for <code>health check</code> like interval, timeout, and retires. For this example, you are specifying a retry of a maximum of 5 times every 5-second interval with a timeout of 5 seconds. All this has been highlighted in yellow in the above code snippet.</p>
<p>There is also the <code>service_completed_successfully</code> option. This option specifies that a dependency is expected to run to successful completion before starting a dependent service. It is another option you can use if you deem it is the right one. For this example, you will use the <code>serivice_healthy</code> option as specified in the above docker-compose file.</p>
<p>When you run <code>docker compose up</code>, Docker Compose will start the <code>db</code> service first, followed by the <code>api</code> service. This ensures that the PostgreSQL database runs before your Node.js application attempts to connect to it.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/docker-compose-depends-on/03docker-compose-depends-on-healthy.jpg" title="With Docker compose depends_on and condition service_healthy you cannot specify the startup order of the services and the dependency" alt="With Docker compose depends_on and condition service_healthy you cannot specify the startup order of the services and the dependency" />
<p>As seen above, the Node.js API this time only started after the Postgres database had started and was deemed healthy by the <code>pg_isready</code> tool that tried to connect using the <code>postgres</code> user. So once you see this log, you can go to <code>http://localhost/quotes</code> and you are sure to see the output on the database. Which takes us to the end of this beginner's guide.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2024/02/docker-compose-depends-on/#conclusion">#</a></h2>
<p>The <code>depends_on</code> option in Docker Compose is a valuable tool for ensuring that services start-up in the correct order with dependiences in a healthy state. By specifying dependencies between services, you can avoid errors and ensure your application functions seamlessly.</p>
<blockquote>
<p>However, it's important to remember that <code>depends_on</code> only controls the startup order and does not guarantee service readiness by default. Use additional tools or techniques, such as health checks, to verify the availability of dependent services before starting services that rely on them.</p>
</blockquote>
<p>By understanding and effectively using <code>depends_on</code>, you can streamline the development and deployment of your multi-container applications, ensuring they run smoothly and reliably. I hope you learned the proper way to use docker compose depends on, keep containerizing and using docker compose more effectively!</p>
How to create a text summarizer API using Gemini on Vertex AI with Node.js a step-by-step guide [Part 2]2024-02-22T12:47:42Zhttps://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/<p>Gemini by Google is a powerful LLM and in this tutorial, you will use the Gemini Pro 1.0 version to summarize text from a URL. In the previous <a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/">part</a> you learned how to set up a GCP project, try out the prompt on Vertex AI studio and then try to code on the CLI. In this part, you will refactor and converter that code to take in a URL, scrape its content, and use it to create the summary, let's get going!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs-api/01gemini-vertex-ai-nodejs-api.jpg" title="How to create a text summarizer API using Gemini on Vertex AI with Node.js a step-by-step guide [Part 2]" alt="How to create a text summarizer API using Gemini on Vertex AI with Node.js a step-by-step guide [Part 2]" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#where-we-left-in-the-last-part">Where we left in the last part</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#build-the-node.js-api">Build the Node.js API</a>
<ul>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#create-gemini.js-file">Create gemini.js file</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#add-scraper.js-file">Add scraper.js file</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#new-cli.js">New cli.js</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#build-the-express.js-api">Build the Express.js API</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#conclusion">Conclusion</a></li>
</ul>
<h2 id="where-we-left-in-the-last-part" tabindex="-1">Where we left in the last part <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#where-we-left-in-the-last-part">#</a></h2>
<p>From the last part, you have a folder called <code>summarizer-gemini</code> which has the <code>@google-cloud/vertexai</code> NPM module installed and <code>cli.js</code> file that can summarize the static text which is in the same file. When you run <code>node –no-warnings cli.js</code>, it will show you an output similar to the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/17cli-output-sync.jpg" title="Better one shot non-streamed output after changing the code to work in a sync manner" alt="Better one shot non-streamed output after changing the code to work in a sync manner" />
<p>After the quick recap, in the next section, you will build the API step-by-step starting with some code refactoring and reorganization. Then you will add a scraper and glue everything up with two entry points, one is a CLI and another one is a Web App with API.</p>
<h2 id="build-the-node.js-api" tabindex="-1">Build the Node.js API <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#build-the-node.js-api">#</a></h2>
<p>As the first task for this part, you will refactor the code from <code>cli.js</code> to another file called <code>gemini.js</code>.</p>
<h3 id="create-gemini.js-file" tabindex="-1">Create gemini.js file <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#create-gemini.js-file">#</a></h3>
<p>Create a new file called <code>gemini.js</code> and it will have the following code (which is similar to the <code>cli.js</code> file):</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> VertexAI <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@google-cloud/vertexai'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> vertex_ai <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VertexAI</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">project</span><span class="token operator">:</span> <span class="token string">'gemini-api-414910'</span><span class="token punctuation">,</span> <span class="token literal-property property">location</span><span class="token operator">:</span> <span class="token string">'us-central1'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> model <span class="token operator">=</span> <span class="token string">'gemini-pro'</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> generativeModel <span class="token operator">=</span> vertex_ai<span class="token punctuation">.</span>preview<span class="token punctuation">.</span><span class="token function">getGenerativeModel</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">model</span><span class="token operator">:</span> model<span class="token punctuation">,</span><br /> <span class="token literal-property property">generation_config</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">"max_output_tokens"</span><span class="token operator">:</span> <span class="token number">2048</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"temperature"</span><span class="token operator">:</span> <span class="token number">0.9</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"top_p"</span><span class="token operator">:</span> <span class="token number">1</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">safety_settings</span><span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span><br /> <span class="token string-property property">"category"</span><span class="token operator">:</span> <span class="token string">"HARM_CATEGORY_HATE_SPEECH"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"threshold"</span><span class="token operator">:</span> <span class="token string">"BLOCK_MEDIUM_AND_ABOVE"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span><br /> <span class="token string-property property">"category"</span><span class="token operator">:</span> <span class="token string">"HARM_CATEGORY_DANGEROUS_CONTENT"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"threshold"</span><span class="token operator">:</span> <span class="token string">"BLOCK_MEDIUM_AND_ABOVE"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span><br /> <span class="token string-property property">"category"</span><span class="token operator">:</span> <span class="token string">"HARM_CATEGORY_SEXUALLY_EXPLICIT"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"threshold"</span><span class="token operator">:</span> <span class="token string">"BLOCK_MEDIUM_AND_ABOVE"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span><br /> <span class="token string-property property">"category"</span><span class="token operator">:</span> <span class="token string">"HARM_CATEGORY_HARASSMENT"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"threshold"</span><span class="token operator">:</span> <span class="token string">"BLOCK_MEDIUM_AND_ABOVE"</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">]</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getSummary</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> prompt <span class="token operator">=</span> <span class="token string">'As an expert writer with more than a decade of experience please summarize the following in under 125 words words. You are allowed to rephrase given the summary means the same as the original text:\n\n'</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> req <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">contents</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">role</span><span class="token operator">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span> <span class="token literal-property property">parts</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>prompt<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>text<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">const</span> resp <span class="token operator">=</span> <span class="token keyword">await</span> generativeModel<span class="token punctuation">.</span><span class="token function">generateContent</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> summary <span class="token operator">=</span> resp<span class="token punctuation">.</span>response<span class="token operator">?.</span>candidates<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>content<span class="token operator">?.</span>parts<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>text<span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> summary<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br /> getSummary<br /><span class="token punctuation">}</span></code></pre>
<p>The things that have changed here is, that you have renamed the <code>getContent</code> function to <code>getSummary</code>. Then you have also removed the static text that had news about removing waste from waterways to a new variable called <code>text</code>. The <code>text</code> variable is passed in as a parameter to the <code>getSummary</code> function which makes it dynamic. Then you expose the get summary with the <code>module.exports</code> so that it can be used with require in any other file and get the returned summary.</p>
<p>In the next part, you will add a basic scraper using Axios and Cheerio (packaged together as axrio).</p>
<h3 id="add-scraper.js-file" tabindex="-1">Add scraper.js file <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#add-scraper.js-file">#</a></h3>
<p>As the aim is to scrape content from a given URL, you will need to add a new NPM package. It is a mixture of <a href="https://axios-http.com/">Axios</a> and <a href="https://cheerio.js.org/">Cheerio</a> called <a href="https://www.npmjs.com/package/@geshan/axrio">Axrio</a>. The readme shows how easy it is to use to scrape any given web page. To install <code>axrio</code> you can run the following:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">--save</span> @geshan/axrio</code></pre>
<p>Running the <code>npm install</code> will result in something as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs-api/02install-axrio.jpg" title="Install axrio with NPM to scrape any web page" alt="Install axrio with NPM to scrape any web page" />
<p>After that you can create a new file named <code>scraper.js</code> which should have the following content:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> axrio <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@geshan/axrio'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getContents</span><span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> timeoutInMs <span class="token operator">=</span> <span class="token number">2000</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> $ <span class="token operator">=</span> <span class="token keyword">await</span> axrio<span class="token punctuation">.</span><span class="token function">getPage</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> timeoutInMs<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">const</span> bodyContents <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'body'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">contents</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">element</span> <span class="token operator">=></span> element<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'tag'</span> <span class="token operator">?</span> <span class="token function">$</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> bodyContents<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error '</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br /> getContents<br /><span class="token punctuation">}</span></code></pre>
<p>Let’s analyze the contents of this file, first, you require the <code>axrio</code> package. After that, a function named <code>getContents</code> is defined that takes in a URL parameter. In that function, you load the page contents using Axrio to a <code>$</code> const. Then you loop through all the nodes of the <code>body</code> tag. If the element is a <code>tag</code> (not a <code>script</code>) it adds it to the array (with the map). At the end, it joins all the pieces with a space in between them.</p>
<p>That is the contents of the page and it returns it. In case of any error, it logs the error and returns an empty string. To test this out you will create a new <code>cli.js</code> that will use both the scraper and Gemini files, next.</p>
<h3 id="new-cli.js" tabindex="-1">New cli.js <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#new-cli.js">#</a></h3>
<p>Now let’s glue up the Scraper and the Gemini service from the new <code>cli.js</code>. The new <code>cli.js</code> will look like the below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> scraper <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./scraper'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> summaryGenerator <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./gemini'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> url <span class="token operator">=</span> process<span class="token punctuation">.</span>argv<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token string">'https://7news.com.au/news/travellers-arriving-in-nsw-urged-to-check-luggage-for-unwanted-stowaway-c-13642953'</span><span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Getting summary for url: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> \n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> pageContents <span class="token operator">=</span> <span class="token keyword">await</span> scraper<span class="token punctuation">.</span><span class="token function">getContents</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>pageContents<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Could not get data from the given URL'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">await</span> summaryGenerator<span class="token punctuation">.</span><span class="token function">getSummary</span><span class="token punctuation">(</span>pageContents<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here, you first require the <code>scraper.js</code> and the <code>gemini.js</code> as <code>summaryGenerator</code>. Then you have an async <a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIEF</a> - Immediately Invoked Function Expression which parses the URL from the CLI parameters. If the URL is not provided it falls back to a News post from 7News. Then it prints the URL it is going to use for scraping and ultimately generating a summary.</p>
<p>After that, it sends the URL to the scraper’s <code>getContents</code> function to get the contents of that web page. If there is no content (even due to an error) it returns <code>could not get data from the given URL</code> else it sends the page contents to the <code>getSummary</code> of the <code>gemini.js</code> file to get the summary.</p>
<p>If you run this script with <code>node --no-warnings cli.js https://7news.com.au/news/advice-for-swifties-on-getting-to-taylor-swifts-eras-tour-shows-at-sydney-olympic-park-c-13672302</code> it will show something like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs-api/03updated-cli.jpg" title="New CLI file that can take in the URL scrape it and send out the summary" alt="New CLI file that can take in the URL scrape it and send out the summary" />
<p>Now the summarizer is working in the CLI, if you don’t provide a URL it will fallback to the 7News luggage URL. There is a two-second timeout for fetching the page so it will throw an error for slow websites. There is no validation of the URL and other things can be made better too. In the next section, you will add it working as an API.</p>
<h3 id="build-the-express.js-api" tabindex="-1">Build the Express.js API <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#build-the-express.js-api">#</a></h3>
<p>To build the API layer on your summarizer using Gemini you will need to install Express.js first with:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">--save</span> express</code></pre>
<p>It will look like the below when express is installed with NPM:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs-api/04install-express.jpg" title="Install latest Express.js with npm install" alt="Install latest Express.js with npm install" />
<p>Then you can add a file named <code>index.js</code> on the root with the following contents:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> scraper <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./scraper'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> summaryGenerator <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./gemini'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> port <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token string">'3000'</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'alive'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/summary'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> url <span class="token operator">=</span> req<span class="token punctuation">.</span>query<span class="token operator">?.</span>url <span class="token operator">||</span> <span class="token string">'https://7news.com.au/news/travellers-arriving-in-nsw-urged-to-check-luggage-for-unwanted-stowaway-c-13642953'</span><span class="token punctuation">;</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//validates if given string is a valid URL</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">provider URL </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is not a valid URL</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Getting summary for url: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> \n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> pageContents <span class="token operator">=</span> <span class="token keyword">await</span> scraper<span class="token punctuation">.</span><span class="token function">getContents</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>pageContents<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">501</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Could not get data properly from the given URL'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <br /> <span class="token punctuation">}</span><br /> <span class="token keyword">const</span> summary <span class="token operator">=</span> <span class="token keyword">await</span> summaryGenerator<span class="token punctuation">.</span><span class="token function">getSummary</span><span class="token punctuation">(</span>pageContents<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> summary <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Listening to requests on http://localhost:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In this file that has a web server with Express.js, you first require all 3 components needed to make the summarizer API work. Those are the express instance, scraper, and the <code>gemini.js</code> file required as the <code>summaryGenerator</code> const.</p>
<p>Then, you instantiate a new express app as the <code>app</code> const and pull in the port from the environment variable. If the environment variable of <code>PORT</code> is not set you fall back to port <code>3000</code>.</p>
<p>The first route you have added for the Express app is <code>/</code> which returns a JSON object with a <code>message</code> key that has the value <code>alive</code>. This acts like a health check for the summarizer API.</p>
<p>After that the bulk of the work is taking place in the <code>/summary</code> GET API route. Here you try to get the <code>url</code> from the query parameter <code>url</code> if not found, you fall back to the news story about luggage in NSW by 7News. It also checks if the given string is a valid URL using the <code>new URL</code> construct. If it is not a valid URL the API responds with a status code of <code>400</code> and a relevant message.</p>
<p>Then you log the URL to know which web page is being scraped. Subsequently, you scrape the content of that URL’s web page by passing the URL in the scraper’s <code>getContent</code> function. It will return the contents of the page if things go fine else it will come back with an empty string. The case of the empty string being returned will translate into a 501 response with the message <code>Could not get data properly from the given URL</code>. This can happen if the URL takes more than 2 seconds to respond or the data cannot be easily parsed by the scraper.</p>
<p>If all goes well it will respond with the summary in the <code>summary</code> key of the response. At the end of the file the web server is started with the <code>app.listen</code> call with a log when the server starts.</p>
<p>You can run it with <code>node index.js</code>, for local development you can also use <a href="https://geshan.com.np/blog/2021/02/nodemon/">nodemon</a>. You can also add it as the <code>npm start</code> script in the <code>package.json</code> file’s script section as highlighted below:</p>
<pre class="language-js"><code class="language-js"><span class="highlight-line"><span class="token string-property property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token string-property property">"start"</span><span class="token operator">:</span> <span class="token string">"node index.js"</span><span class="token punctuation">,</span></mark><br /><span class="highlight-line"> <span class="token string-property property">"test"</span><span class="token operator">:</span> <span class="token string">"echo \"Error: no test specified\" && exit 1"</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span><span class="token punctuation">,</span></span></code></pre>
<p>Then you can run <code>npm start</code> on the root of the folder which will give the following output:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs-api/05npm-start.jpg" title="Start the summarizer API Express.js server with npm start" alt="Start the summarizer API Express.js server with npm start" />
<p>After that if you go to your favorite browser and hit <code>http://localhost:3000/summary?url=https://developer.mozilla.org/en-US/docs/Glossary/IIFE</code> on the address bar you will see something like the below (if everything went fine):</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs-api/06gemini-summarizer-api-working.jpg" title="Gemini based text summarizer API working with Node.js and Express" alt="Gemini based text summarizer API working with Node.js and Express" />
<p>There you have it, you have successfully converted the sample that you got from Vertex AI - <code>Get Code</code> section into a working API. You can easily deploy it to a service like Cloud Run on GCP with or without Dockerzing the app. If you push your code to GitHub you can also use <a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/">Cloud Shell Editor</a> to get and deploy the code to Cloud Run, which can be a topic for another blog post. To deploy this code on Cloud Run, some other things will need to be dynamic or picked from the environment variables like the GCP project and GCP location.</p>
<p>The code is also available as an open-source <a href="https://github.com/geshan/summarizer-gemini">GitHub repository</a> for your reference.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs-api/#conclusion">#</a></h2>
<p>In part 2 of this tutorial, you were able to convert the sample code into a full-fledged API. You also have a quick way to test out any URL using the modified <code>cli.js</code> file.</p>
<p>I hope it gives you a solid base to create your Gen AI apps using the Gemini API on Vertex AI in the Google Cloud Platform. This is just scratching the surface, with the right prompts you can create APIs that can do many things like categorize text, generate other text, etc. The possibilities are endless. I hope you learned a useful skill.</p>
How to create a text summarizer using Gemini over Vertex AI with Node.js a step-by-step guide [Part 1]2024-02-21T12:45:42Zhttps://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/<p>Gemini by Google is a powerful multimodal Large Language Model (LLM) capable of taking images, videos, and text as input and generating text and images. <a href="https://gemini.google.com/">Gemini</a> has 3 versions Nano, Pro, and Ultra. For this post, you will use Gemini Pro 1.0 via <a href="https://cloud.google.com/vertex-ai">Vertex AI</a> to create summarizer then run it on the CLI using Node.js, let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/01gemini-vertex-ai-nodejs.jpg" title="How to create a text summarizer using Gemini over Vertex AI with Node.js a step-by-step guide [Part 1]" alt="How to create a text summarizer using Gemini over Vertex AI with Node.js a step-by-step guide [Part 1]" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#prerequisites">Prerequisites</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#summarizer-with-gemini-api-on-vertex-ai">Summarizer with Gemini API on Vertex AI</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#run-the-summarizer-in-the-cli-with-nodejs">Run the summarizer in the CLI with Node.js</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#next-steps">Next steps</a></li>
<li><a href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#conclusion">Conclusion</a></li>
</ul>
<h2 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#prerequisites">#</a></h2>
<p>Before getting your hands dirty with the code, below are some prerequisites you should have:</p>
<ul>
<li>You should have a running Google Cloud Account, GCP gives $300 <a href="https://cloud.google.com/free">free</a> for 90 days for new accounts. Be aware of the <a href="https://cloud.google.com/vertex-ai/pricing">Vertex AI pricing</a> for Gemini APIs.</li>
<li>A basic understanding of Node.js and the NPM package manager is expected. You should have Node and NPM CLIs running on your local. The code has been tested with Node 20.x.</li>
<li>You have the <code>gcloud</code> <a href="https://cloud.google.com/sdk/gcloud">cli</a> working on your machine.</li>
<li>Some git knowledge will be good to have but not required</li>
</ul>
<p>Next, you will start using the Gemini Pro API over Vertex AI.</p>
<h2 id="summarizer-with-gemini-api-on-vertex-ai" tabindex="-1">Summarizer with Gemini API on Vertex AI <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#summarizer-with-gemini-api-on-vertex-ai">#</a></h2>
<p>Given the prerequisites are mentioned, the first task for you is to test out the summarizer app on Vertex AI. To do ths, you will first login to your Google Cloud Platform <a href="https://console.cloud.google.com/">console</a> and create a new project as follows on the <a href="https://console.cloud.google.com/projectcreate">Project Create</a> page:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/02gcp-create-project.jpg" title="Create a new GCP project" alt="Create a new GCP project" />
<p>You can name the project <code>gemini-api</code> as seen above and click the “Create” button selecting the right billing account (and organization if you have any relevant one).</p>
<p>It will take some time and the project will be created with a notification about it, you can select the project from the notification (under the bell icon) as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/03gcp-select-project.jpg" title="Select your newly created GCP projct to use it for building the summarizer" alt="Select your newly created GCP projct to use it for building the summarizer" />
<p>After that, search for <code>vertex ai</code> on the search bar and click the <code>Vertex AI</code> option from the inline search results as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/04vertex-ai-search.jpg" title="Search for vertex ai on the GCP console search bar" alt="Search for vertex ai on the GCP console search bar" />
<p>On the Vertex AI page, at the left sidebar scroll a bit down and click the <code>Language</code> option <code>Vertex AI Studio</code>, you will be given the option to enable the Vertex AI APIs for the project as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/05enable-apis.jpg" title="Enable the Vertex AI APIs to use Gemini 1.0 Pro LLM" alt="Enable the Vertex AI APIs to use Gemini 1.0 Pro LLM" />
<p>Click <code>Enable</code> on the above screen, it will show <code>Enabled</code> with a green tick then close it, and then in the second overlay click “Agree and Continue” as follows</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/06vertex-ai-studio-agree.jpg" title="Agree the Vertex AI terms and conditions to move head" alt="Agree the Vertex AI terms and conditions to move head" />
<p>After that, click <code>Text Prompt</code> in the Generate text card found below “Create New Prompt” as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/07text-prompt.jpg" title="Select text prompt to create a summarizer" alt="Select text prompt to create a summarizer" />
<p>In the screen that has the <code>Prompt</code> text box paste the following:</p>
<pre class="language-js"><code class="language-js">As an expert writer <span class="token keyword">with</span> more than a decade <span class="token keyword">of</span> experience please summarize the following <span class="token keyword">in</span> under <span class="token number">125</span> words words<span class="token punctuation">.</span> You are allowed to rephrase given the summary means the same <span class="token keyword">as</span> the original text<span class="token operator">:</span><br /><br />The TerraCycle Global Foundation reached an impressive milestone last month<span class="token punctuation">,</span> announcing that they’ve removed over <span class="token number">2</span> million pounds <span class="token keyword">of</span> waste from rivers<span class="token punctuation">,</span> canals<span class="token punctuation">,</span> and waterways<span class="token punctuation">.</span><br /><br />Since its founding<span class="token punctuation">,</span> the nonprofit organization has targeted ocean pollution right at its source—waterways<span class="token punctuation">.</span> When polluted<span class="token punctuation">,</span> they send waste directly to oceans<span class="token punctuation">,</span> harming sea life and the environment<span class="token punctuation">.</span> Over <span class="token number">1000</span> tons have been diverted and recycled<span class="token punctuation">.</span><br /><br />And<span class="token punctuation">,</span> because the Foundation is founded by New Jersey<span class="token operator">-</span>based TerraCycle—a two decades<span class="token operator">-</span>old company known <span class="token keyword">for</span> turning plastic waste into useful items <span class="token keyword">for</span> sale—none <span class="token keyword">of</span> the litter collected ever goes to waste<span class="token punctuation">.</span> <span class="token punctuation">(</span>See a link to their cool bracelets below<span class="token punctuation">.</span><span class="token punctuation">)</span><br /><br />Operating <span class="token keyword">in</span> canals throughout Bangkok<span class="token punctuation">,</span> Thailand<span class="token punctuation">,</span> TerraCycle’s “world<span class="token operator">-</span><span class="token keyword">class</span> <span class="token class-name">river</span> waste prevention systems” are implemented <span class="token keyword">with</span> the local community and governments to address the complex challenge <span class="token keyword">of</span> collecting waste before it enters and pollutes global aquatic systems<span class="token punctuation">.</span><br /><br />The Foundation is currently operating wildlife<span class="token operator">-</span>safe river traps <span class="token keyword">in</span> Thai canals to recover waste directly from the water<span class="token punctuation">.</span> The waste is then sorted<span class="token punctuation">,</span> and plastics are separated and recycled<span class="token punctuation">.</span><br /><br />“We take a holistic approach to reducing plastic waste <span class="token keyword">in</span> waterways<span class="token punctuation">,</span>” said James Scott<span class="token punctuation">,</span> Executive Director <span class="token keyword">of</span> the TerraCycle Global Foundation<span class="token punctuation">.</span> “Our operations provide safe<span class="token punctuation">,</span> stable employment <span class="token keyword">for</span> members <span class="token keyword">of</span> the local Lat Phrao community <span class="token keyword">in</span> Bangkok <span class="token keyword">while</span> creating cleaner and healthier environments <span class="token keyword">for</span> communities along the canal<span class="token punctuation">.</span>”<br /><br />TerraCycle Global Foundation’s River Trap<br />“Reaching <span class="token keyword">this</span> waste removal milestone is only the beginning <span class="token keyword">of</span> the Foundation’s work to clean our oceans and preserve the planet<span class="token punctuation">.</span>”<br /><br /><span class="token constant">CHECK</span> <span class="token constant">OUT</span><span class="token operator">:</span> Ocean CleanUp Launches Huge System <span class="token keyword">in</span> Pacific Garbage Patch to Clean a Football Field Every <span class="token number">5</span> Seconds<br /><br />Indeed<span class="token punctuation">,</span> last year the Foundation made a Clinton Global Initiative ‘Commitment to Action’<span class="token punctuation">,</span> <span class="token keyword">with</span> a project that prevents ocean waste<span class="token punctuation">.</span> They pledged to replicate and scale its successful canal cleanup model <span class="token keyword">in</span> a <span class="token keyword">new</span> <span class="token class-name">region</span> <span class="token keyword">in</span> Southeast Asia<span class="token punctuation">,</span> and establish a material recovery center <span class="token keyword">as</span> a central hub <span class="token keyword">for</span> waste management and educational programs<span class="token punctuation">.</span><br /><br />Check out all the recycling going on at TerraCycle<span class="token punctuation">,</span> especially their cool beaded bracelets that help collect <span class="token number">20</span><span class="token operator">-</span>lbs <span class="token keyword">of</span> plastic waste <span class="token keyword">with</span> proceeds from every purchase—and <span class="token number">100</span><span class="token operator">%</span> <span class="token keyword">of</span> it is made from diverted litter<span class="token punctuation">.</span></code></pre>
<p>The above text is from a news story on <a href="https://www.goodnewsnetwork.org/nonprofit-diverts-an-ocean-plastic-tide-removing-2-million-pounds-of-trash-from-waterways/">Good News Network</a> and the magic sauce, the prompt is:</p>
<pre class="language-js"><code class="language-js">As an expert writer <span class="token keyword">with</span> more than a decade <span class="token keyword">of</span> experience please summarize the following <span class="token keyword">in</span> under <span class="token number">125</span> words words<span class="token punctuation">.</span> You are allowed to rephrase given the summary means the same <span class="token keyword">as</span> the original text<span class="token operator">:</span></code></pre>
<p>After you paste it, click the <code>Submit</code> button toward the end of the page and it will look as follows after the summarization is done:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/08vertex-ai-gemini-pro-summary.jpg" title="Text summary generated on Vertex AI with Gemni 1.0 Pro model" alt="Text summary generated on Vertex AI with Gemni 1.0 Pro model" />
<p>Hurray! You have created a useful summarizer with very little effort in almost no time. You can click the <code>pencil</code> icon and save it if you like.</p>
<p>Make sure that the model is <code>Gemini 1.0 Pro</code> and you can change the region as per your choice. If you like you can play around with the other parameters like temperature to fine-tune your output. You are also welcome to peep into the <code>Advance settings</code> like Top-K and Top-P to get a better result. You can learn more about them in this blog post about these <a href="https://ivibudh.medium.com/a-guide-to-controlling-llm-model-output-exploring-top-k-top-p-and-temperature-parameters-ed6a31313910">LLM parameters</a>. You can also update the <code>Safety Settings</code> if you would like to block things like hate speech, dangerous content, etc.</p>
<p>In the next section, you will pull in the code provided to make the summarizer work in the CLI.</p>
<h2 id="run-the-summarizer-in-the-cli-with-node.js" tabindex="-1">Run the summarizer in the CLI with Node.js <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#run-the-summarizer-in-the-cli-with-node.js">#</a></h2>
<p>It is good that your proof concept is running on Vertex AI but your users cannot use it just like that. For that, you will need some code to eventually expose your summarizer as an API to your ultimate users. Vertex AI has some generated code available to make your POC into a working app. To get the code, click the <code>Get Code</code> link toward the top right of the vertex AI studio page:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/09vertex-ai-get-code.jpg" title="Vertex AI get code button" alt="Vertex AI get code button" />
<p>Then click <code>Node.js</code> as this is a Node.js example on the slider that comes on the right side of your screen:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/10vertex-ai-nodejs-code.jpg" title="Vertex AI Node.js code sample for your simple text summarizer" alt="Vertex AI Node.js code sample for your simple text summarizer" />
<p>After that, go to a directory and create a new directory named <code>summarizer-gemini</code>, which on a Nix-based system will be <code>mkdir summarizer-gemini</code> the to go to the directory <code>cd summarizer-gemini</code>.</p>
<p>In that folder, run <code>npm init -y</code> and you will see something like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/11npm-init.jpg" title="Result of npm init to initiate a Node.js project" alt="Result of npm init to initiate a Node.js project" />
<p>After that, you can run the following commands as seen on the Vertex AI’s get code slider:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @google-cloud/vertexai</code></pre>
<p>This command will install the Google Cloud’s Vertex AI NPM package on your local machine. That will look like the following when completed:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/12npm-install-gcp-vertex-ai.jpg" title="Installing the GCP Vertex AI npm package" alt="Installing the GCP Vertex AI npm package" />
<p>Subsequently, run the following to log in to your Gcloud account from your CLI:</p>
<pre class="language-bash"><code class="language-bash">gcloud auth application-default login</code></pre>
<p>This will open a browser to allow the Google Auth library to access your GCP account from your CLI.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/13gcp-sign-in.jpg" title="Sign into GCP after running gcloud auth" alt="Sign into GCP after running gcloud auth" />
<p>Then you will need to allow the Google Auth Library</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/14gcp-allow.jpg" title="Allow GCP gcloud auth to access your Google account details" alt="Allow GCP gcloud auth to access your Google account details" />
<p>Once that is done you can copy page the whole code that begins with:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span>VertexAI<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@google-cloud/vertexai'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>To a file named <code>cli.js</code> in the folder you are in, it will look something like the below when done correctly:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/15vscode-cli-js.jpg" title="File structure for cli.js in VS Code" alt="File structure for cli.js in VS Code" />
<p>Now in your CLI, you can run <code>node –no-warnings cli.js</code>, it will show you an output similar to the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/16cli-output-stream.jpg" title="Streamed output of the sample code copied from the Vertex AI Studio interface" alt="Streamed output of the sample code copied from the Vertex AI Studio interface" />
<p>As the output is streamed, it is not very useful to be used in the CLI. Now, you can change the <code>generateContent</code> function to look like the below to make it a sync call rather than a streaming one:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">generateContent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> prompt <span class="token operator">=</span> <span class="token string">'As an expert writer with more than a decade of experience please summarize the following in under 125 words words. You are allowed to rephrase given the summary means the same as the original text:\n\n'</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> req <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">contents</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">role</span><span class="token operator">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span> <span class="token literal-property property">parts</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>prompt<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">The TerraCycle Global Foundation reached an impressive milestone last month, announcing that they’ve removed over 2 million pounds of waste from rivers, canals, and waterways.\n\nSince its founding, the nonprofit organization has targeted ocean pollution right at its source—waterways. When polluted, they send waste directly to oceans, harming sea life and the environment. Over 1000 tons have been diverted and recycled.\n\nAnd, because the Foundation is founded by New Jersey-based TerraCycle—a two decades-old company known for turning plastic waste into useful items for sale—none of the litter collected ever goes to waste. (See a link to their cool bracelets below.)\n\n\nOperating in canals throughout Bangkok, Thailand, TerraCycle’s “world-class river waste prevention systems” are implemented with the local community and governments to address the complex challenge of collecting waste before it enters and pollutes global aquatic systems.\n\nThe Foundation is currently operating wildlife-safe river traps in Thai canals to recover waste directly from the water. The waste is then sorted, and plastics are separated and recycled.\n\n“We take a holistic approach to reducing plastic waste in waterways,” said James Scott, Executive Director of the TerraCycle Global Foundation. “Our operations provide safe, stable employment for members of the local Lat Phrao community in Bangkok while creating cleaner and healthier environments for communities along the canal.”\n\n\nTerraCycle Global Foundation’s River Trap\n“Reaching this waste removal milestone is only the beginning of the Foundation’s work to clean our oceans and preserve the planet.”\n\nCHECK OUT: Ocean CleanUp Launches Huge System in Pacific Garbage Patch to Clean a Football Field Every 5 Seconds\n\nIndeed, last year the Foundation made a Clinton Global Initiative ‘Commitment to Action’, with a project that prevents ocean waste. They pledged to replicate and scale its successful canal cleanup model in a new region in Southeast Asia, and establish a material recovery center as a central hub for waste management and educational programs.\n\nCheck out all the recycling going on at TerraCycle, especially their cool beaded bracelets that help collect 20-lbs of plastic waste with proceeds from every purchase—and 100% of it is made from diverted litter.</span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">const</span> resp <span class="token operator">=</span> <span class="token keyword">await</span> generativeModel<span class="token punctuation">.</span><span class="token function">generateContent</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> summary <span class="token operator">=</span> resp<span class="token punctuation">.</span>response<span class="token operator">?.</span>candidates<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>content<span class="token operator">?.</span>parts<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>text<span class="token punctuation">;</span><br /><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>summary<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Let’s analyze the things that changed. First, you introduced a const called <code>prompt</code> that has the prompt to summarize the text. This makes separating the prompt from the text to work on. Then you used it as part of the request.</p>
<p>In place of the <code>generateContentStream</code> you have replaced it with the <code>generateContent</code> to get the final result compared to following a stream approach. You can configure the request params as per the official <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini#gemini-pro">docs</a>. After the response is received, you pull out the text and print it on the screen with a <code>console.log</code>. It looks like the following when you again run <code>node –no-warnings cli.js</code>:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/gemini-vertex-ai-nodejs/17cli-output-sync.jpg" title="Better one shot non-streamed output after changing the code to work in a sync manner" alt="Better one shot non-streamed output after changing the code to work in a sync manner" />
<p>You need the <code>--no warnings</code> to not print any warnings about the fetch object. There you have a basic example of creating a summarizer in your CLI.</p>
<h2 id="next-steps" tabindex="-1">Next steps <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#next-steps">#</a></h2>
<p>For this post, it will feel a bit static and restricted. To change the input text to get a summary you will need to change the file and run the command again. Thereby, in the next part of this series, you will be able to input a URL to an API. Then the system will scrape the text from that URL and then summarize it.</p>
<p>It will involve some code refactoring and restructuring to make the code reusable, stay tuned for part 2 where you will convert this code to a more flexible solution with an Express JS API. If you are eager to look at the API code, it is available as an open-source <a href="https://github.com/geshan/summarizer-gemini">GitHub repository</a>.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2024/02/gemini-vertex-ai-nodejs/#conclusion">#</a></h2>
<p>In this post, you learned how to play around with the Vertex AI interface to create a Gemini Pro 1.0 powered summarizer. Then, you pulled in the code to your local on a <code>cli.js</code> file and changed the code to give a synchronous output compared to a streaming one. I hope it was a good start, more goodness to follow in the next part. Keep exploring Gen AI and Gemini!</p>
How to use Google Cloud Shell Editor to deploy a project from GitHub to Cloud Run2024-01-22T12:45:42Zhttps://geshan.com.np/blog/2024/01/cloud-shell-editor/<p>Google Cloud Shell Editor is like having a VS code editor inside of your browser that can be used to get most things done. In this post, you will use the Google Cloud Shell editor to pull in code from an open-source repository and deploy it to Cloud Run without leaving your browser. Let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/cloud-shell-editor/01cloud-shell-editor.jpg" title="How to use Google Cloud Shell Editor to deploy a project from GitHub to Cloud Run" alt="How to use Google Cloud Shell Editor to deploy a project from GitHub to Cloud Run" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#google-cloud-shell-terminal">Google Cloud Shell Terminal</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#cloud-shell-editor">Cloud Shell Editor</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#example-code-to-pull-in-from-github">Example code to pull in from GitHub</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#make-a-small-change">Make a small change</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#deploy-code-to-cloud-run">Deploy code to Cloud Run</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#check-the-working-app">Check the working app</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#conclusion">Conclusion</a></li>
</ul>
<h2 id="google-cloud-shell-terminal" tabindex="-1">Google Cloud Shell Terminal <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#google-cloud-shell-terminal">#</a></h2>
<p>Google Cloud Shell is your online command center for Google Cloud. It's a pre-configured command line environment accessible directly from your web browser. You click an icon on the top right corner with a <code>>_</code> sign, after you log in to your Google Cloud console to activate Cloud shell. After it is activated, it will open Cloud shell and you have access to a full-fledged interactive shell environment with bash, as seen below</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/02google-cloud-shell-terminal.jpg" title="Google Cloud Shell terminal window in action" alt="Google Cloud Shell terminal window in action" />
<p>When it first appears, it is only half of the screen. You can pull it and expand it to be as long as you like. I have made it cover almost all of the browse space available.</p>
<p>You get a temporary Compute Engine Virtual machine that can be used for a maximum of 60 hours a week (official doc says <a href="https://cloud.google.com/shell/docs/quotas-limits">50</a> hours). It has <code>gcloud</code> command the Google Cloud SDK pre-installed and also has languages like Python, Java, Go and Node.js installed on it. You also get <a href="https://cloud.google.com/shell">5 GB</a> of persistent storage. If you need a CLI tool, chances are it might already be there. If it is not there you can <code>apt-get</code> and get it but remember it is an ephemeral machine.</p>
<p>In addition to the shell terminal, you also get the Google Cloud Shell Editor which is a version of VS code inside the browser. That is discussed next with a code example which is deployed to Google Cloud Run.</p>
<h2 id="cloud-shell-editor" tabindex="-1">Cloud Shell Editor <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#cloud-shell-editor">#</a></h2>
<p>Google Cloud Shell Editor is a web-based code editor that's included with every Cloud Shell instance. It lets you develop, build, debug, and deploy cloud-based applications directly from your browser, without needing to set up any local development environment. This online code editor has support the languages like JavaScript (Node.js), Java, Python and Go lang with features like syntax highlighting, code completion, linting, and debugging. You can access the Cloud Shell Code Editor by clicking the <code>Open Editor</code> button</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/03open-editor.jpg" title="Open the Google Cloud Shell editor" alt="Open the Google Cloud Shell editor" />
<p>At first, you will get the legacy editor, to use the latest editor click the <code>Try the new editor</code> button, as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/04try-new-editor.jpg" title="Use the new Google Cloud Shell Editor - not the legacy one" alt="Use the new Google Cloud Shell Editor - not the legacy one" />
<p>If all goes well, after you authorize and the machine is provisioned in some seconds (not minutes), you will see the Google Cloud Shell Editor as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/05google-cloud-shell-editor.jpg" title="The new Google Cloud Shell Editor ready for use, looks similar to VS Code" alt="The new Google Cloud Shell Editor ready for use, looks similar to VS Code" />
<p>Hurray! You have a full-on VS-Code like editor inside your browser that great. In the next part, you will pull in a simple Node.js Express app and make some changes to it then deploy it to Google Cloud Run without leaving the browser window.</p>
<h2 id="example-code-to-pull-in-from-github" tabindex="-1">Example code to pull in from GitHub <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#example-code-to-pull-in-from-github">#</a></h2>
<p>For this tutorial, you will use an example that creates a fictional landing page for a podcast called the “Eventually Podcast”. You can give your email address and <code>Sign up</code> to know when the podcast is launched, pretty simple. You can read about how it is made in this blog post about <a href="https://geshan.com.np/blog/2021/05/nodejs-express-tutorial/">Next.js Express tutorial</a>.</p>
<p>To pull in the code on your Google Cloud Shell machine VM you can run the following commands within the Google Cloud Shell Editor’s CLI editor. You can start a terminal window by clicking the hamburger menu then going to <code>Terminal > New Terminal</code> or hitting the relevant shortcut as per your operating system.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/06cloud-shell-editor-terminal.jpg" title="Open the terminal inside the Google Cloud Shell editor" alt="Open the terminal inside the Google Cloud Shell editor" />
<p>After that, you will see then the terminal inside your Google Cloud Shell environment as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/07cloud-shell-editor-terminal-open.jpg" title="Access the terminal inside the Google Cloud Shell editor" alt="Access the terminal inside the Google Cloud Shell editor" />
<p>You can use the main terminal if you choose to but staying inside the editor and using this terminal is better. You can run the following commands to get the needed code from GitHub in the <code>projects</code> folder:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> projects <span class="token operator">&&</span> <span class="token builtin class-name">cd</span> projects<br /><span class="token function">git</span> clone <span class="token parameter variable">--branch</span> no-docker https://github.com/geshan/nodejs-express-tutorial.git</code></pre>
<p>The first line creates the <code>projects</code> folder and goes into it, the second line clones the repository needed for this example. There are a couple of things you should understand about the <code>git clone</code>. First is that it is cloning the <code>no-docker</code> branch, not the master branch and the second is it is using the <code>https</code> url not the <code>git@github.com…</code> URL to make things simple and jump the authentication hoop. When the commands are done it will look like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/08cloud-shell-git-clone.jpg" title="Create projects folder and clone the GitHub repository using HTTPs" alt="Create projects folder and clone the GitHub repository using HTTPs" />
<p>Great! At this point, you have the code that you need in your Google Cloud Shell VM. Next, you will make a small change to get a feel of using the Google Cloud Shell Editor.</p>
<h2 id="make-a-small-change" tabindex="-1">Make a small change <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#make-a-small-change">#</a></h2>
<p>Given the needed code is on the virtual machine at <code>~/projects/nodejs-express-tutorial</code>, it can be added to the code editor following the instructions below:</p>
<ul>
<li>Open <code>Explorer</code> (if it is not open) - the first icon on the editor’s left bar</li>
<li>Then click <code>Open Folder</code></li>
<li>After that add <code>projects</code> to the path (which will be your home folder)</li>
<li>Then select <code>nodejs-express-tutorial</code></li>
<li>After that hit ok</li>
</ul>
<p>That looks like the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/09cloud-editor-open-project.jpg" title="Open the project in the cloud shell editor" alt="Open the project in the cloud shell editor" />
<p>It will take some time and the code will be loaded on the editor, open the <code>index.js</code> file as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/10cloud-shell-editor-open-file.jpg" title="Open the right file from the project in the cloud shell editor" alt="Open the right file from the project in the cloud shell editor" />
<p>As you can see the syntax highlight is also there for the JavaScript file. Then add <code> on Google Cloud Run.</code> on the line no. 18 after <code>amazing people</code> as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/11edit-file.jpg" title="Edit the open file to add desired content on the Google Cloud Shell Editor" alt="Edit the open file to add desired content on the Google Cloud Shell Editor" />
<p>Now save the file, it is as easy as using an editor on your local machine. You can bring up the terminal again and see if the changes are reflected with a <code>git status</code> command which will show something like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/12file-edited.jpg" title="Save the edited file on the Google Cloud Shell Editor" alt="Save the edited file on the Google Cloud Shell Editor" />
<p>In the next section, you will deploy this code to Google Cloud Run.</p>
<h2 id="deploy-code-to-cloud-run" tabindex="-1">Deploy code to Cloud Run <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#deploy-code-to-cloud-run">#</a></h2>
<p>As everything is integrated and authenticated. To deploy the code (even without dockerizing) you can run the following <code>gcloud</code> command and it will deploy the app to Google Cloud Run from the source. As this is a <code>Node.js</code> application which is one of the <a href="https://cloud.google.com/run/docs/deploying-source-code">supported languages</a> to be from source by Google Cloud Run, it will work even without having a Dockerfile.</p>
<pre class="language-bash"><code class="language-bash">gcloud run deploy eventually-podcast <span class="token parameter variable">--source</span> <span class="token builtin class-name">.</span> --allow-unauthenticated <span class="token parameter variable">--region</span><span class="token operator">=</span>us-central1</code></pre>
<p>Here you are asking the service to be called <code>eventually-podcast</code> when deploying to Cloud Run from the source code available in the current folder <code>.</code> and make it accessible without any authentication. For this example, you chose <code>us-central1</code> as the region, which can be changed depending on where you want to deploy the app. You can specify other parameters too like memory, cpu, and other. Read it in the <a href="https://cloud.google.com/sdk/gcloud/reference/run/deploy">official documentation</a> of <code>gcloud run deploy</code> or ask Duet AI. When the command is executed from the <code>nodejs-express-tutorial</code> folder it will look like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/13deploy-to-cloud-run.jpg" title="Start deploying the code to Google Cloud Run from source which used Buildpacks" alt="Start deploying the code to Google Cloud Run from source which used Buildpacks" />
<p>It will take some minutes to build the image from the source using <a href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/%E2%80%8Bhttps://cloud.google.com/docs/buildpacks/overview">buildpacks</a> and then deploy it to Google Cloud Run. You might need to authorize some permissions if you are doing so for the first time. Many things happen in the background to get this job done. Once done it will look as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/14deployed-to-cloud-run.jpg" title="Code is deployed to Cloud Run and you get a working HTTPS URL to try out" alt="Code is deployed to Cloud Run and you get a working HTTPS URL to try out" />
<p>You will see a Cloud Run URL ending with <code>.run.app</code> where the app is running now.</p>
<h2 id="check-the-working-app" tabindex="-1">Check the working app <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#check-the-working-app">#</a></h2>
<p>When you open the given URL on your browser you can see the app running on Google Cloud Run and also the change you made (highlighted in the screenshot below) as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/15running-app.jpg" title="The eventually podcast app is running successfully on Google Cloud Run" alt="The eventually podcast app is running successfully on Google Cloud Run" />
<p>You can verify it by going to your Cloud Run services list page or by clicking the <code>Cloud Code</code> icon (the 6th icon on the left side) and then expanding <code>Cloud Run</code> in it as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/cloud-shell-editor/16check-editor-cloud-run.jpg" title="Quick check of the Cloud Run service in Cloud Code inside the Google Cloud Shell Editor" alt="Quick check of the Cloud Run service in Cloud Code inside the Google Cloud Shell Editor" />
<p>There you have it, a step-by-step guide to getting code from any open-source GitHub repository (without generating any SSH key), then making a small change and deploying it to Google Cloud Run without leaving your browser.</p>
<p>As a side note:</p>
<blockquote>
<p>Google Cloud Shell Editor can be one of the fastest and easiest ways to use and experience Google’s <a href="https://cloud.google.com/duet-ai">Duet AI</a> for developers on a code editor.</p>
</blockquote>
<p>That could be a good topic for another blog post. Anyhow, you can try some of your Gen AI and prompt engineering chops following this post on <a href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/">Node.js and Duet AI on VS Code</a>.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2024/01/cloud-shell-editor/#conclusion">#</a></h2>
<p>In this post, you were introduced to Google Cloud Shell Terminal and Google Cloud Shell Editor. Then you pulled code from a GitHub repository and used the Cloud Shell Editor to make a minor change. After that, you deployed it successfully to Google Cloud Run with a single command, without using Docker. Finally, you could see the app working with an HTTPS URL that ended in <code>.run.app</code>. As the app has unauthenticated access, it can be accessed by anyone in the world.</p>
<p>I hope you will utilize both the Cloud Shell terminal and Cloud Shell editor to your advantage and business benefits. Keep learning!</p>
How to Use Enums in TypeScript for Cleaner Code2024-01-02T12:35:42Zhttps://geshan.com.np/blog/2024/01/typescript-enum/<p>TypeScript has emerged as a powerful tool that brings static typing to JavaScript, enhancing code maintainability and reducing bugs. One of TypeScript's features that significantly contributes to code clarity and organization is Enum, short for enumeration. In this blog post, you will learn more about Enums in TypeScript, why and how to use them, let’s get going!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/typescript-enum/01typescript-enum.jpg" title="How to Use Enums in TypeScript for Cleaner Code" alt="How to Use Enums in TypeScript for Cleaner Code" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#what-are-enums">What are Enums</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#why-use-typescript-enums">Why Use TypeScript Enums</a>
<ul>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#readability-and-intention">Readability and Intention</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#code-maintainability">Code Maintainability</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#autocompletion-support">Autocompletion Support</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#avoiding-magic-values">Avoiding Magic Values</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#how-to-use-enums-in-typescript">How to Use Enums in TypeScript</a>
<ul>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#example---order-status">Example - Order Status</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#order-status-with-numeric-enums">Order Status with Numeric Enums</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#order-status-with-string-enums">Order Status with String Enums</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#heterogeneous-enums">Heterogeneous Enums</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#more-about-enums">More about Enums</a></li>
<li><a href="https://geshan.com.np/blog/2024/01/typescript-enum/#conclusion">Conclusion</a></li>
</ul>
<h2 id="what-are-enums" tabindex="-1">What are Enums <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#what-are-enums">#</a></h2>
<p>Enums, short for enumerations, are a feature of languages that allows developers to define a set of named constants, allowing developers to represent a group of related values in a more meaningful and readable way. These named constants represent a distinct set of values that are related in some way.</p>
<p>Enums are available in other languages like <a href="https://weyprecht.de/2019/10/16/enums-in-csharp-and-java/">Java and C#</a>, even databases like <a href="https://dev.mysql.com/doc/refman/8.0/en/enum.html">MySQL</a> and <a href="https://dev.mysql.com/doc/refman/8.0/en/enum.html">Postgres</a> have Enum type. Unfortunately, JavaScript does not support Enums natively, even though a workaround can be to use a regular JavaScript object as a proxy Enum. TypeScript, on the other hand, has support for Enums. In TypeScript, Enum makes it possible to create a symbolic name for a set of values, providing more meaningful names to improve code readability.</p>
<p>Let's dive deeper into the structure of Enums in TypeScript. Enum declarations begin with the <code>enum</code> keyword, followed by the name of the enumeration. Inside the braces, you list the possible values of the enum, each separated by a comma. Below is a simple Enum for traffic lights:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">enum</span> TrafficLights <span class="token punctuation">{</span><br /> Red<span class="token punctuation">,</span><br /> Yello<span class="token punctuation">,</span><br /> Green<span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p>In this example, you have created an enum named <code>TrafficLights</code> with three possible values: <code>Red</code>, <code>Yello</code>, and <code>Green</code>. By default, TypeScript assigns numeric values starting from 0 to each enum member. In this case, <code>Red</code> will have the value 0, <code>Yellow</code> will have 1, and so on.</p>
<p>In the next section, you will learn why to use Enums in Typescript.</p>
<h2 id="why-use-typescript-enums" tabindex="-1">Why Use TypeScript Enums <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#why-use-typescript-enums">#</a></h2>
<p>Now that you understand what Enums are in general and have seen a simple TypeScript example, let's explore why you might want to use them in your TypeScript projects.</p>
<h3 id="readability-and-intention" tabindex="-1">Readability and Intention <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#readability-and-intention">#</a></h3>
<p>Enums improve the readability of your code by replacing magic numbers or strings with meaningful names. Instead of using <code>if (status === 1)</code>, you can write <code>if (status === OrderStatus.Processing)</code>, making your code self-explanatory and reducing the likelihood of errors.</p>
<h3 id="code-maintainability" tabindex="-1">Code Maintainability <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#code-maintainability">#</a></h3>
<p>Enums make your code more maintainable by centralizing the definition of related constants. If you ever need to add, remove, or modify a value, you can do so in one place – the enum declaration; rather than hunting through your codebase for every occurrence of a particular constant. It is also helpful to replace existing values by searching for the enum.</p>
<h3 id="autocompletion-support" tabindex="-1">Autocompletion Support <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#autocompletion-support">#</a></h3>
<p>Integrated development environments (IDEs) that support TypeScript, such as <a href="https://code.visualstudio.com/">Visual Studio Code</a>, provide autocompletion for enum members. This accelerates the coding process, minimizes the risk of typos, and decreases the possibility of introducing a bug.</p>
<h3 id="avoiding-magic-values" tabindex="-1">Avoiding Magic Values <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#avoiding-magic-values">#</a></h3>
<p>You can avoid magic values with Enums. Using Enums properly "magic values" scattered throughout your code can be centralized in a single location. Magic values are hard-coded constants that lack clear context. Enums provide a named representation, adding clarity to your codebase. For example <code>if (platform === 0)</code> is much harder to read vs <code>if (platform === platforms.mobile)</code>, here the 0 is the magic value.</p>
<p>In the next part, you will learn how to use Typescript Enums with an example of order statuses.</p>
<h2 id="how-to-use-enums-in-typescript" tabindex="-1">How to Use Enums in TypeScript <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#how-to-use-enums-in-typescript">#</a></h2>
<p>Now that you have established the benefits of using Enums, let's walk through practical examples of how to implement them in TypeScript. For this, you will use order statuses as an example. If you have placed an order on any e-commerce website it will have some status like placed, processing (packed), shipped, and delivered for the happy path. It can also have other statuses like canceled, returned, etc but we will not include them.</p>
<h3 id="example---order-status" tabindex="-1">Example - Order Status <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#example---order-status">#</a></h3>
<p>Consider a scenario where you're working on an e-commerce platform, and you need to represent different order statuses. Instead of using numeric or string literals, Enums provide a cleaner solution.</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">enum</span> OrderStatus <span class="token punctuation">{</span><br /> Placed<span class="token punctuation">,</span><br /> Packed<span class="token punctuation">,</span><br /> Shipped<span class="token punctuation">,</span><br /> Delivered<span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p>In this example, we've defined an enum named <code>OrderStatus</code> with four possible values: <code>Placed</code>, <code>Packed</code>, <code>Shipped</code>, and <code>Delivered</code>. More on what the values will be for the above Emum in the next segment.</p>
<h3 id="order-status-with-numeric-enums" tabindex="-1">Order Status with Numeric Enums <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#order-status-with-numeric-enums">#</a></h3>
<p>By default, TypeScript assigns numeric values starting from 0 to each enum member. So, for the above example, <code>Placed</code> will have a value of 0 and <code>Delivered</code> will have value of 3. However, you can customize these values if needed, as seen below.</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">enum</span> OrderStatus <span class="token punctuation">{</span><br /> Placed <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span><br /> Packed <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">,</span><br /> Shipped <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">,</span><br /> Delivered <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now, <code>OrderStatus.Placed</code> will have the value 1, <code>OrderStatus.Packed</code> will have 2, and so on. The following code will also behave the same as the above example:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">enum</span> OrderStatus <span class="token punctuation">{</span><br /> Placed <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span><br /> Packed<span class="token punctuation">,</span><br /> Shipped<span class="token punctuation">,</span><br /> Delivered<span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p>You can try out all the examples locally with TypeScript or on the <a href="https://www.typescriptlang.org/play">TypeScript Playground</a> without installing anything on your local machine. Below is an example of the auto-incremental values running on the <a href="https://www.typescriptlang.org/play?#code/KYOwrgtgBA8gTgE2HAygFwIZrAZygbwCgooAFAGwwGNgEoBeKARgBpizqBrWtklACwCWAB2E92AEWDlBAN2TiAvoUJUA9iBxrywAHTk1AcwAU8JKkzYcu0l1oBKIA">TypeScript Playground</a>:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/typescript-enum/02typescript-enum-playground.jpg" title="Order Status TypeScript enum example running on TypeScript playground" alt="Order Status TypeScript enum example running on TypeScript playground" />
<p>You can run all the code examples in this blog post on TypeScript playgroud to see how it run and what it compiles to in the form of JavaScript. Next, you will look into Order Status enum with strings.</p>
<h3 id="order-status-with-string-enums" tabindex="-1">Order Status with String Enums <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#order-status-with-string-enums">#</a></h3>
<p>In addition to numeric enums, TypeScript supports string enums, where each enum member is initialized with a string value.</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">enum</span> OrderStatus <span class="token punctuation">{</span><br /> Pending <span class="token operator">=</span> <span class="token string">"Pending"</span><span class="token punctuation">,</span><br /> Processing <span class="token operator">=</span> <span class="token string">"Processing"</span><span class="token punctuation">,</span><br /> Shipped <span class="token operator">=</span> <span class="token string">"Shipped"</span><span class="token punctuation">,</span><br /> Delivered <span class="token operator">=</span> <span class="token string">"Delivered"</span><span class="token punctuation">,</span><br /> Canceled <span class="token operator">=</span> <span class="token string">"Canceled"</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p>This approach can be beneficial when you want more descriptive values or use the enum values as keys in an object.</p>
<p>Next, you will learn about more concepts related to TypeScript emums like Heteregenous enums and extracting object types of Enums.</p>
<h3 id="heterogeneous-enums" tabindex="-1">Heterogeneous Enums <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#heterogeneous-enums">#</a></h3>
<p>Unlike other languages, TypeScript allows for heterogeneous enums, where some members have numeric values, and others have string values. You can also mix up numbers and strings as the values for Enums which is called Heterogenous Enums, as seen below:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword">enum</span> Status <span class="token punctuation">{</span><br /> Success <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">,</span><br /> NotFound <span class="token operator">=</span> <span class="token string">"Not Found"</span><span class="token punctuation">,</span><br /> Error <span class="token operator">=</span> <span class="token string">"Internal Server Error"</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p>This flexibility can be useful in scenarios where a mix of data types is required, but that is not recommended in the official <a href="https://www.typescriptlang.org/docs/handbook/enums.html#heterogeneous-enums">TypeScript docs</a>. Subsequently, there are some useful concepts about TypeScript Enums that would be great for you to know about.</p>
<h2 id="more-about-enums" tabindex="-1">More about Enums <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#more-about-enums">#</a></h2>
<p>There are more things to Enums than the ones already mentioned in this post. It would be useful for you to know about <a href="https://levelup.gitconnected.com/introduction-to-typescript-enums-const-and-ambient-enums-1fe686b67495">Ambient Enums</a>, which are basically like a redefinition of existing enums. Similarly it would be helpful to know about <a href="https://www.digitalocean.com/community/tutorials/how-to-use-enums-in-typescript#extracting-the-object-type-of-enums">exrtracting object type of Enums</a>, that can make it easier to use Enum as a Type in TypeScript. Other couple of interesting things about Enums that would be handy for you to know are, how enums are represented on <a href="https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-runtime">runtime</a> and <a href="https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-compile-time">compile time</a>.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2024/01/typescript-enum/#conclusion">#</a></h2>
<p>In conclusion, Enums in TypeScript are a powerful tool for improving code readability, maintainability, and intention. By providing named constants, Enums make your code more self-explanatory and less error-prone. Whether you're representing order statuses, HTTP status codes, or any other set of related values, Enums offer a cleaner and more organized solution.</p>
<p>As a software engineer, leveraging Enums in TypeScript is not just a best practice; it's a step towards writing more robust and maintainable code. Embrace Enums, and witness the transformation of your code into a clearer and more expressive form.</p>
2023 year in review: Blogging, public speaking, interviews, building communities, etc2023-12-26T12:47:53Zhttps://geshan.com.np/blog/2023/12/review-2023/<p>Like <a href="https://geshan.com.np/blog/2022/12/recap-2022/">previous</a> <a href="https://geshan.com.np/blog/2021/12/recap-2021/">years</a>, I would like to write a quick recap of the things I have done in 2023. Taking some time to reflect on the things achieved this year from a professional standpoint would be a great look back, let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/review-2023/01review-2023.jpg" title="2023 year in review: Blogging, public speaking, interviews, building communities, etc" alt="2023 year in review: Blogging, public speaking, interviews, building communities, etc" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#highlights">Highlights</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#interviews-for-2-podcasts">Interviews for 2 podcasts</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#harkas-podcast">Harka’s podcast</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#careersy-podcast">Careersy podcast</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#blogging-and-writing-in-2023">Blogging and writing in 2023</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#geshan.com.np">Geshan.com.np</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#most-viewed-blog-posts-of-2023">Most viewed blog posts of 2023</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#traffic-is-down-(thanks-to-llms%2C-especially-chatgpt)">Traffic is down (thanks to LLMs, especially ChatGPT)</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#community-building">Community building</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#gdg-cloud-sydney">GDG Cloud Sydney</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#other-gdg-communities">Other GDG communities</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#gdg-darwin">GDG Darwin</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#gdg-canberra">GDG Canberra</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#more-coming-soon">More coming soon</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#mentor-at-gdg-devfest-kathmandu">Mentor at GDG Devfest Kathmandu</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#talks-and-events">Talks and events</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#helped-organize-google-i%2Fo-extended-sydney">Helped organize Google I/O Extended Sydney</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#conferences">Conferences</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#side-project---speakers-camp">Side project - Speakers camp</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/review-2023/#conclusion">Conclusion</a></li>
</ul>
<h2 id="highlights" tabindex="-1">Highlights <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#highlights">#</a></h2>
<p>Below are some of the highlights of the year 2023 from a professional and tech point of view:</p>
<ul>
<li>I was invited for 2 interviews, one in Dubai (taken in the Nepali language) by Harka for his podcast and another one in Sydney by Eli (from <a href="https://www.careersycoaching.com/">Carrersy</a>)</li>
<li>Published 25+1 (this review) posts on this blog. Compared to 2023, in the past 12 months, the traffic has gone up by 5% or so but the last 3 months is showing a downward trend. Thanks to LLMs and Google Algorithm changes. I have written 1 post for Simply Wall St. tech and 3 posts for Meticulous, this year.</li>
<li>The side project for the year was Speakers Camp, where I helped foster 3+ new speakers, more on this later.</li>
<li>I did 7 public talks this year with 1 being virtual. One of the talks was in Melbourne and another one was in Brisbane. I also did 2 panel discussions as well.</li>
<li>Growing communities has been a big thing for me this year, especially with a focus on GDG Cloud Sydney community (and other GDG Communities)</li>
</ul>
<p>I have been with Simply Wall St. since 2022, it will be 2 years soon that I have been working with SWS and it has been a great experience. The <a href="https://medium.com/simplywallst/flexible-working-at-simply-wall-st-a13d5a4fdd82">flexibility</a> SWS provides is unparalleled and the <a href="https://medium.com/simplywallst/5-compelling-reasons-to-work-for-simply-wall-st-tech-49ab9878b283">tech side of things</a> is amazing too. Which leads us to the 2 podcast interview I did this year.</p>
<h2 id="interviews-for-2-podcasts" tabindex="-1">Interviews for 2 podcasts <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#interviews-for-2-podcasts">#</a></h2>
<p>I did 2 podcast interviews (some people did not reply to my email, sadly). At least on one, I self-invited myself, and on the other Eli invited me to be a guest. The first one was Harka’s podcast as discussed next:</p>
<h3 id="harka%E2%80%99s-podcast" tabindex="-1">Harka’s podcast <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#harka%E2%80%99s-podcast">#</a></h3>
<p>Harka Lopchan (not Sampang) started his <a href="https://www.youtube.com/channel/UC5qC4CaoAhJnqrL4NaJWHrw">podcast</a> in early 2022. When we went to Dubai in March this year, I self-invited myself as a guest on his podcast. I knew him when I lived in Dubai and we had met a few times before 2018. We discussed a lot of things in this 1 hr 2 min episode from immigration to tech and from Nepal’s economy to blogging. It is a good podcast for anyone interested in migrating to a new country and tech. This podcast is in Nepali language, below is the YouTube video and Spotify:</p>
<div style="position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%; margin-bottom: 1rem;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/GasVbk2wUHY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;" allowfullscreen=""></iframe>
</div>
<p>If you would like to listen to the audio version, it is available on <a href="https://open.spotify.com/episode/1mGcMCcB0zdMWIkbWY4cUo">Spotify</a></p>
<p>For the amount of time, energy, and dedication he devotes to this podcast, I wish him 100K and more subscribers soon. Now there are Nepali celebrities, singers, and other personalities as guests in his podcast. I wish him all the best.</p>
<p>Then in April, I did another podcast with Eli which was released in May.</p>
<h3 id="careersy-podcast" tabindex="-1">Careersy podcast <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#careersy-podcast">#</a></h3>
<p><a href="https://www.linkedin.com/in/eligunduz/?originalSubdomain=au">Eli</a> works as a recruiter for Atlassian and he also runs Carrersy for career coaching. It was good to have that discussion with him regarding my career, tech stuff, and things like working remotely. The podcast is below and on <a href="https://open.spotify.com/episode/14PKPmvxiB2fgIfkQTtuZ5">Spotify</a> too:</p>
<p><a href="https://open.spotify.com/episode/14PKPmvxiB2fgIfkQTtuZ5">https://open.spotify.com/episode/14PKPmvxiB2fgIfkQTtuZ5</a></p>
<div style="left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;"><iframe src="https://open.spotify.com/embed/episode/14PKPmvxiB2fgIfkQTtuZ5/video?utm_source=oembed" style="top: 0; left: 0; width: 100%; height: 100%; position: absolute; border: 0;" allowfullscreen="" scrolling="no" allow="clipboard-write; encrypted-media; fullscreen; picture-in-picture;"></iframe></div>
<p>Let’s discuss some writing and blogging in the next section.</p>
<h2 id="blogging-and-writing-in-2023" tabindex="-1">Blogging and writing in 2023 <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#blogging-and-writing-in-2023">#</a></h2>
<p>I have been blogging since 2007, crunching some numbers in the 227 posts on this blog it has 347306 words with an average of ~1530 words per post. More on this, next.</p>
<h3 id="geshan.com.np" tabindex="-1"><a href="http://geshan.com.np/">Geshan.com.np</a> <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#geshan.com.np">#</a></h3>
<p>This year I wrote 25+1 (this review) posts with 2 posts each month 3 in July and 3 in December were the 2 exception months. This year I have written posts on <a href="https://geshan.com.np/blog/categories/postgres/">PostgreSQL</a>, <a href="https://geshan.com.np/blog/2023/12/review-2023/%E2%80%8B/blog/categories/jest/">Jest</a>, Axios, <a href="https://geshan.com.np/blog/categories/typescript/">Typescript</a>, Node.js, <a href="https://geshan.com.np/blog/categories/gen-ai/">Gen AI</a>, Next.js, <a href="https://geshan.com.np/blog/categories/docker/">Docker</a> and other people skills topics too. Even though the traffic has reduced significantly I aim to keep writing blogs in 2024.</p>
<h3 id="most-viewed-blog-posts-of-2023" tabindex="-1">Most viewed blog posts of 2023 <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#most-viewed-blog-posts-of-2023">#</a></h3>
<p>The 5 most popular (by views) posts written in this year 2023 are as follows:</p>
<ul>
<li><a href="https://geshan.com.np/blog/2023/01/nextjs-docker/">How to use Next.js with Docker and Docker compose a beginner's guide</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/">How to run MongoDB with Docker and Docker Compose a Step-by-Step guide</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/">A beginner's guide to running Elasticsearch with Docker and Docker Compose</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/">How to use environment variables in Next.js (includes a working example app)</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/">How to use ON DELETE CASCADE in Postgres with an example</a></li>
</ul>
<p>Looks like things about Docker get more views :). Next, I will discuss the traffic trends of this blog.</p>
<h3 id="traffic-is-down-(thanks-to-llms%2C-especially-chatgpt)" tabindex="-1">Traffic is down (thanks to LLMs, especially ChatGPT) <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#traffic-is-down-(thanks-to-llms%2C-especially-chatgpt)">#</a></h3>
<p>I think it is a mix of multiple things but possibly Google’s search traffic for core technical topics has gone down this year after Nov 2022. For example, if you want to run a specific test with Jest, earlier most software engineers would Google it (where my blog post would pop up in the top 5) but now many software engineers will ask the same question to a LLM like ChatGPT or Bard. This surely means traffic to tech blogs like mine and even stack overflow have decreased a lot in 2023. In an official <a href="https://stackoverflow.blog/2023/08/08/insights-into-stack-overflows-traffic/">blog post</a>, Stack Overflow revealed:</p>
<blockquote>
<p>Conversely, in April of this year, we saw an above average traffic decrease (~14%), which we can likely attribute to developers trying GPT-4 after it was released in March. Our traffic also changes based on search algorithms, which have a big influence on how our content is discovered.</p>
</blockquote>
<p>I am not going to go into numbers but the situation is bleak, particularly in the last 4 months which might be triggered by Google’s algorithm changes too. Anyhow I will strive to write the usual 2 blog posts a month in 2024 unless I find that it is not beneficial to the readers/audience anymore. Speaking of which, similar web paints the below picture of this blog which was at 358,133 global rank last year this time.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/02geshan-blog-2023.jpg" title="Traffic for this blog as mentioned by Similar web" alt="Traffic for this blog as mentioned by Similar web" />
<p>In the next section, coming out of the virtual world let’s step into “IRL - in real life” of communities and meet humans in the flesh.</p>
<h2 id="community-building" tabindex="-1">Community building <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#community-building">#</a></h2>
<p>Your network is your net worth, full stop. If you do not expand your network, when there is a need (particularly a professional one), it will be difficult for you to get the best outcome for the situation. That is also one of the reasons I have dove into community building and nurturing this year.</p>
<h3 id="gdg-cloud-sydney" tabindex="-1">GDG Cloud Sydney <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#gdg-cloud-sydney">#</a></h3>
<p>I started hosting the <a href="https://www.meetup.com/gdgcloudsydney/">GDC Cloud Sydney</a> meetup in March 2023 this year. After I became a co-organizer and assembled a great organizing team, we have done at least <a href="https://www.meetup.com/gdgcloudsydney/events/?type=past">one meetup</a> a month till Nov-2023.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/04gdg-cloud-sydney.jpg" title="Random photo infront of the Google logo in one of the GDG Cloud Sydney meetups" alt="Random photo infront of the Google logo in one of the GDG Cloud Sydney meetups" />
<p>When I looked back at the stats of the meetup group, from March 2023 more than 900 people have joined the group and we have seen more than 1450 RSVPs for our meetups. We have also reached more than 3000 members in mid-October this year.</p>
<h3 id="other-gdg-communities" tabindex="-1">Other GDG communities <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#other-gdg-communities">#</a></h3>
<p>I have also helped establish or revive existing Google Developer Groups (GDG) communities across Australia. With a big help from Matt, the community manager at Google this feat has been enjoyable.</p>
<h4 id="gdg-darwin" tabindex="-1">GDG Darwin <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#gdg-darwin">#</a></h4>
<p>I helped <a href="https://www.linkedin.com/in/sujanrdm/?originalSubdomain=au">Sujan</a> start <a href="https://www.meetup.com/gdg-darwin/">GDG Darwin</a> which did <a href="https://www.meetup.com/gdg-darwin/events/?type=past">3+ meetups</a> in 2023. Great job by Sujan and the team. It is amazing that Sujan needed only minor guidance and he has taken this big task on his own and executed it successfully. Kudos, to more meetups in Darwin for GDG Darwin.</p>
<h4 id="gdg-canberra" tabindex="-1">GDG Canberra <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#gdg-canberra">#</a></h4>
<p>Then, there is the recently started <a href="https://www.meetup.com/gdg-canberra/">GDG Canberra</a> headed by <a href="https://www.linkedin.com/in/kiran-gautam/">Kiran</a>. The team in Canberra did the <a href="https://www.meetup.com/gdg-canberra/events/297134615/">first meetup</a> in November and another one is planned for late <a href="https://www.meetup.com/gdg-canberra/events/298065370/">Jan-2024</a>. Also a big thanks to <a href="https://www.abhishekhmaharjan.com/">Abhishek</a>, <a href="https://www.linkedin.com/in/ramesh-dhoju-6311849b/?originalSubdomain=au">Ramesh</a>, and <a href="https://www.linkedin.com/in/tijanmdr/?originalSubdomain=au">Tijan</a> for helping out at GDG Canberra being amazing co-organizers.</p>
<h4 id="more-coming-soon" tabindex="-1">More coming soon <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#more-coming-soon">#</a></h4>
<p>A couple of GDG groups are brewing in Australia, details to follow. The thing here is you need to be part of the community and real-life (in-person) events are even more important after the 2+ years of isolation we have witnessed due to COVID-19. Hopefully, at least two new GDGs will be formed and active in Australian cities by Q1 of 2024, fingers crossed.</p>
<p>I have been involved in communities since 2006. The main issue for communities not sustaining for long is not having proper backing for financial and operational needs. The other important thing is having great succession planning, if the organizers leave the community should not fall. This is where leaning onto a big company like Google helps sustain communities for a long time.</p>
<h4 id="mentor-at-gdg-devfest-kathmandu" tabindex="-1">Mentor at GDG Devfest Kathmandu <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#mentor-at-gdg-devfest-kathmandu">#</a></h4>
<p>I also got a chance to mentor a couple of speakers for <a href="https://gdg.community.dev/events/details/google-gdg-kathmandu-presents-devfest-kathmandu-2023/">GDG Devfest Kathmandu</a>, which I suppose was helpful for the speakers. Thanks to <a href="https://www.linkedin.com/in/bibekdhkl/">Bibek</a> and the GDG Kathmandu team for this opportunity.</p>
<p>Next, we will discuss the talks I have given and events I have been a part of.</p>
<h2 id="talks-and-events" tabindex="-1">Talks and events <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#talks-and-events">#</a></h2>
<p>I also got a chance to do 7 talks (one virtual) and 2-panel discussions. I was a judge at a hackathon too. I used 3 talks across 7 events and one of them was presented virtually and another one was done at a university.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/03speaking.jpg" title="Select speaking engagements from 2023" alt="Select speaking engagements from 2023" />
<p>I was also part of 2 panel discussions one at Google Sydney in Apr-2023 about Career and groundbreaking technologies.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/05panels.jpg" title="A couple of Panel discussions from 2023" alt="A couple of Panel discussions from 2023" />
<p>The second panel discussion was at GDG Devfest Brisbane which included things like career, and other techy things. You can watch the view of that panel discussion below:</p>
<div style="position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%; margin-bottom: 1rem;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/SVdpDh2uwuQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;" allowfullscreen=""></iframe>
</div>
<p>I also participated as a Judge for a Hackathon at Dented Code Academy in April. It was an interesting event to be a part of:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/06judge.jpg" title="Judging a hackathon at Dented Code Academy" alt="Judging a hackathon at Dented Code Academy" />
<p>Now let's move on to organizing an event a conference in Sydney.</p>
<h3 id="helped-organize-google-i%2Fo-extended-sydney" tabindex="-1">Helped organize Google I/O Extended Sydney <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#helped-organize-google-i%2Fo-extended-sydney">#</a></h3>
<p>Speaking of conferences, I also helped organize <a href="https://gdg.community.dev/events/details/google-gdg-sydney-presents-google-io-2023-extended/">Google I/O Extended Sydney 2023</a>. My contribution was mostly on the part of selecting talks and helping shape the content rather than the logistics side of things. The logistics part of the day was very well managed by <a href="https://www.linkedin.com/in/arorakartik/">Kartik Arora</a> and a team of volunteers which I helped to assemble.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/07gio-extended.jpg" title="A team photo after the Google I/O Extended Sydney 2023 conference" alt="A team photo after the Google I/O Extended Sydney 2023 conference" />
<p>I also helped organize an event focused at students liasing with GDSC USyd and GDSC UNSW too.</p>
<p>Time to discuss about conferences, next.</p>
<h3 id="conferences" tabindex="-1">Conferences <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#conferences">#</a></h3>
<p>And speaking more of the conference, I attended 4 conferences this year and spoke at 2 of them. Both the conferences I spoke at were not in Sydney but they were in Australia, one in Melbourne and another one in Brisbane.</p>
<p>I helped organize Google I/O Sydney 2023, so it was obvious that I would attend it (even if it was only in the afternoon). Then in Aug, I attended Cloudflare Connect 2023. The best part of the conference was the discussion with Atlassian co-founder Mike Cannon Brookes.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/08cf-connect.jpg" title="Mike Cannon Brookes at Cloudflare Connect 2023 Sydney" alt="Mike Cannon Brookes at Cloudflare Connect 2023 Sydney" />
<p>I gave a talk at the GDG Devfest Melbourne 2023 in October and the same talk about serverless containers at GDG Devfest Brisbane 2023 in December. Both the conferences were very well organized and visiting Brisbane was a great experience.</p>
<p>Talking about speaking I helped 4 people get into speaking at meetups, that story is next.</p>
<h2 id="side-project---speakers-camp" tabindex="-1">Side project - Speakers camp <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#side-project---speakers-camp">#</a></h2>
<p>I have a side project each year, which does not necessarily need to be code or a product. I like helping people as last year it was Bloggers’ Union, this year it was Speakers Camp. The basic idea is to push, help, and motivate people to get into public speaking of any form, especially speaking at meetups which has a lower bar than speaking at conferences.</p>
<p>The 4 speakers I had helped in some form be it content, delivery, or finding a slot at a meetup were Prasiddha (Pras), Kushal, Sagar, and Ashis. Their talks varied in content, from serverless functions to Machine Learning and Flutter. Below is a clip of Pras thanking me for mentoring/pushing him to do public speaking.</p>
<div style="position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%; margin-bottom: 1rem;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/KxwsOMLEV4Q?si=Ip1sD4l4EX80rvpo&clip=UgkxcO4aoa_V9LQLnftMu7uHdMQQvEeLe-0M&clipt=EImWXhjBwmA" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;" allowfullscreen=""></iframe>
</div>
<p>And some of the other speakers are here too:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/review-2023/09speakers.jpg" title="4 new Nepali tech speakers in Sydney mentored by me in 2023" alt="4 new Nepali tech speakers in Sydney mentored by me in 2023" />
<p>At least two more are in the pipeline for Q1 of 2024, hopefully, more speakers will overcome their fear of public speaking and break into it.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/12/review-2023/#conclusion">#</a></h2>
<p>All in all, this has been a great year in terms of professional things done. I hope to continue blogging, public speaking, organizing meetups, and helping out the community in general in 2024 too.</p>
Good software engineering is about finding a solution at the correct layer with boring technology2023-12-21T12:21:53Zhttps://geshan.com.np/blog/2023/12/good-software-engineering/<p>In the ever-evolving landscape of technology, the importance of good software engineering cannot be overstated. It's the core of efficient, scalable, and maintainable software solutions. While there are various methodologies and practices, a key aspect often overlooked is the art of finding the right solution at the correct layer and level of abstraction. On top of that, reliable software systems are best built with boring technology. You will learn more about these topics in this post, let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/good-software-engineering/01good-software-engineering.jpg" title="Good software engineering is about finding a solution at the correct layer with boring technology" alt="Good software engineering is about finding a solution at the correct layer with boring technology" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#select-the-right-layer-for-your-solution">Select the Right Layer for Your Solution</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#database-vs.-code">Database vs. Code</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#code-layers%3A-controller%2C-service%2C-and-repository">Code Layers: Controller, Service, and Repository</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#code-or-not-code">Code or not code</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#choose-boring-technology">Choose Boring Technology</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#measure-learn-and-adapt">Measure, Learn, and Adapt</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/good-software-engineering/#conclusion">Conclusion</a></li>
</ul>
<p>Good software engineering is not just about writing code that works; it's about writing code that stands the test of time, is easily maintainable, and can adapt to the changing needs of the business. This involves making crucial decisions about where and how different components of your system should interact while it is stable, scaleable, and resilient.</p>
<p>In addition to that, your choice of technology for each layer also plays a vital role in how reliable, easily recoverable, and <a href="https://geshan.com.np/blog/2020/12/software-resilience/">resilient software</a> you can deliver. Another important aspect of this discussion is <a href="https://geshan.com.np/blog/2020/12/software-scalability/">software scalability</a>. In the next section, you will learn about selecting the right layer for your solution.</p>
<h2 id="select-the-right-layer-for-your-solution" tabindex="-1">Select the Right Layer for Your Solution <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#select-the-right-layer-for-your-solution">#</a></h2>
<p>Depending on the context, you will need to find the right layer of the technology for your feature/solution or the fix for a bug. As with most things in software engineering, the best answer is “It depends”. Still, many a time you might want to engineer your solution at the right layer of a <a href="https://www.ibm.com/topics/three-tier-architecture">3 tier or an N-tier</a> application. Let’s explore some of the facets of this realm:</p>
<h3 id="database-vs.-code" tabindex="-1">Database vs. Code <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#database-vs.-code">#</a></h3>
<p>One of the first decisions a software engineer faces is determining where to handle certain aspects of their application logic—whether in the database or the code. While databases are excellent for managing and querying data, they are not the place for complex business logic. Striking the right balance between keeping your database simple and handling logic in your codebase is essential.</p>
<p>Recently I discussed with the team whether a piece of logic can go in as an SQL query or should be in the code. After a quick cost-benefit analysis, putting in the solution as a SQL select query might be a cleaner way to do it but as we know scaling a relational database is a lot more harder than scaling a dockerized application. Thereby, the Slack thread ended in agreeing to place the logic in the application code rather than running it on the database server. Still, you should know that <a href="https://geshan.com.np/blog/2018/12/you-can-do-it-in-sql/">you can do it in SQL</a>, whether to run the logic on the DB server is a choice based on trade-offs as it depends.</p>
<h3 id="code-layers%3A-controller%2C-service%2C-and-repository" tabindex="-1">Code Layers: Controller, Service, and Repository <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#code-layers%3A-controller%2C-service%2C-and-repository">#</a></h3>
<p>Within the codebase, it's crucial to identify the appropriate layer for specific functionalities. The controller layer handles user input, the service layer encapsulates business logic, and the repository layer manages data storage and retrieval. Deciding which layer should house certain functionalities is akin to placing puzzle pieces together, ensuring a cohesive and understandable structure.</p>
<p>Choosing the right layer means understanding the responsibilities of each and keeping them focused on their core tasks. For instance, business logic should reside in the service layer, leaving the controller layer to manage input and output, and the repository layer to handle data operations.</p>
<p>This also points a bit towards the <a href="https://levelup.gitconnected.com/single-responsibility-principle-a-beginners-note-cb1eaba1fecd">single responsibility principle</a>. Anyhow, even if you don’t write strictly object-oriented programming, in any web related work there will always be a route -> linked to a controller of some sort. Some business logic will need to be written somewhere, which is generally a service, and depending on your layers and levels some code will interact with the data layer. The data layer in most cases will be a relational database or a non-relational database. When you write your solution think precisely where how the parts will be spread and how it will affect a later change to the feature.</p>
<h3 id="code-or-not-code" tabindex="-1">Code or not code <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#code-or-not-code">#</a></h3>
<p>Sometimes the solution or bug fix is not in the code it might be in a configuration or a setting. I remember a bug we had many years back with persisting a session. We looked very hard into the code but it turned out to be a configuration on the Memcached server we were using to store the session data for sticky sessions.</p>
<p>Similarly, let's say there is a slow-performing application. You can run 100s of tests and a lot of performance testing to squeeze out the last drop of juice on your application-level code. But that difficult-to-make performant (read faster) issue could be easily solved by adding a couple of database indexes on the right columns or a group of columns which is also called a <a href="https://planetscale.com/learn/courses/mysql-for-developers/indexes/composite-indexes">composite index</a>. The moral of the story is to think a bit outside of the box and try to find a solution outside of the code too.</p>
<p>In the next section, you will learn about <a href="https://mcfunley.com/choose-boring-technology">choosing boring technology</a> where the interesting part is, it helps you sleep much better.</p>
<h2 id="choose-boring-technology" tabindex="-1">Choose Boring Technology <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#choose-boring-technology">#</a></h2>
<p>In the fast-paced world of technology, the allure of using the latest and most cutting-edge tools can be tempting. However, good software engineering often means <a href="https://boringtechnology.club/">choosing boring technology</a>. Boring technology is reliable, well-established, and has a proven track record. If not anything, it gives a much higher chance of you having a good night’s sleep and when you are on-call the phone will not ring much.</p>
<p>While it might not be as exciting as the latest framework, boring technology is more likely to be well-documented, have a large community of users, and provide long-term support. This stability is crucial for the longevity of your software, as it reduces the risk of unexpected issues and makes it easier to find talent familiar with the tools you're using.</p>
<p>Boring technology has very little unknown unknowns, which means if there is an issue it is usually not a completely new issue and can be solved relatively quickly. Again boring technology might mean different things to different teams.</p>
<blockquote>
<p>If a team has been doing Rust for the last 6 years (released in 2015, so possible) then Rust might be a boring technology for them versus a team that has been doing only Javascript (Node.js/Typescript) in the backend for the past 5 years.</p>
</blockquote>
<p>The same can be said for a team using MySQL for 10 years vs a team using MongoDb for 10 years (Mongo released in 2009, so it is possible too).</p>
<p>Still, relying on battle-tested technologies that have been proven to work at a much higher scale and workload than what your company generally has is a much safer bet compared to the new language, framework, or database in the market.</p>
<blockquote>
<p>This does not mean to never try a new technology (language/framework or database), but you should experiment with a new thing in an experiment (that will be used by 100s of people) not the main money earner service of the company. If that service goes down the company loses 1000s of dollars each minute.</p>
</blockquote>
<p>You can also use new things in your side project for learning, so why not? Well, all this depends on the simple principle of measuring, learning, and adapting which is discussed next.</p>
<h2 id="measure%2C-learn%2C-and-adapt" tabindex="-1">Measure, Learn, and Adapt <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#measure%2C-learn%2C-and-adapt">#</a></h2>
<p>Good software engineering involves an iterative process of measurement, learning, and adaptation. Monitoring the performance of your system, gathering user feedback, and learning from both successes and failures are integral parts of the software development lifecycle.</p>
<blockquote>
<p>For instance, even after doing all the tricks in the book if your MySQL or Postgres does not deliver fast enough performance then it is surely time to introduce a layer of caching with an in-memory database like Redis.</p>
</blockquote>
<p>In this case, redis will have a key-value pair or the data you need for that page in a denormalized form.</p>
<p>By measuring the performance of your application, you can identify bottlenecks, optimize code, and improve user experience. User feedback provides valuable insights into how your software is being used and what improvements can be made. Being open to learning from experiences, both positive and negative, allows you to adapt your approach, refine your processes, and continuously enhance your software.</p>
<p>In today’s age application performance monitoring (APM) software also helps you a lot to view logs and see the response times of your software system.</p>
<blockquote>
<p>You can also know the resource consumption of the software you developed and delivered in almost real-time. This helps you roll back a wrong release or course-correct a change you made weeks or even months back in a more empirical way with real data on hand.</p>
</blockquote>
<p>Bottom line, invest in an APM software to know what happening in your software. If dog is a man's best friend, logs are a software engineer's best friend. Embrace <a href="https://geshan.com.np/blog/2019/03/follow-these-logging-best-practices-to-get-the-most-out-of-application-level-logging-slides/">application level logging</a> from today.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/12/good-software-engineering/#conclusion">#</a></h2>
<p>In conclusion, good software engineering is a multifaceted discipline that goes beyond just writing functional code. It involves making informed decisions about where to place different elements of your system, choosing reliable and proven technologies, following established best practices, and embracing a culture of continuous improvement.</p>
<blockquote>
<p>You cannot improve what you cannot measure - Peter Drucker; applies equally to software systems too.</p>
</blockquote>
<p>By selecting the right layer for your solution, choosing boring but reliable technology, and adopting a mindset of measurement and adaptation, you pave the way for software that not only meets current requirements but also evolves with the dynamic nature of technology and business needs.</p>
<p>In essence, good software engineering is about finding the solution at the correct layers and levels, creating a foundation for robust, scalable, and future-proof software systems. Always keep learning!</p>
How to write and deploy a basic Node.js API with Duet AI on VS Code a step-by-step guide2023-12-18T12:15:52Zhttps://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/<p>As developers, we constantly dance between writing code, managing infrastructure, and keeping tabs on deployment and logs. Wouldn't having an AI teammate that simplifies these tasks be amazing? Duet AI is a Google AI tool that acts as your coding buddy and streamlines the development process, for most applications including Node.js. In this post, you will learn how to use Duet AI to write a simple Node.js API application and deploy it on Google Cloud Run.</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/01nodejs-duet-ai-vs-code.jpg" title="How to write and deploy a basic Node.js API with Duet AI on VS Code a step-by-step guide" alt="How to write and deploy a basic Node.js API with Duet AI on VS Code a step-by-step guide" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#install-duet-ai-on-vs-code">Install Duet AI on VS Code</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#writing-a-simple-node.js-api-with-duet-ai">Writing a simple Node.js API with Duet AI</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#deploy-to-cloud-run-with-duet-ai">Deploy to cloud run with Duet AI</a></li>
<li><a href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#conclusion">Conclusion</a></li>
</ul>
<h2 id="install-duet-ai-on-vs-code" tabindex="-1">Install Duet AI on VS Code <a class="direct-link" href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#install-duet-ai-on-vs-code">#</a></h2>
<p>You can install the Google Cloud Code (Duet AI) extension to <a href="https://code.visualstudio.com/">VS Code</a> or IntelliJ/<a href="https://www.jetbrains.com/">JetBrains</a> IDE. For this blog post, you will use VS Code. You can follow the <a href="https://cloud.google.com/code/docs/vscode/install">official guide</a> to install the Code Cloud extension on your VS Code. Make sure you have linked the right Google Cloud Project where you have enabled Duet AI. After the installation, your VS Code should look like the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/02duet-ai-installed.jpg" title="Duet AI (Cloud Code) installed on VS Code" alt="Duet AI (Cloud Code) installed on VS Code" />
<p>Please take note of the things I have highlighted in the screenshot, the Google Cloud Project you are connected to, and the Duet AI Icon on the bottom right of VS Code. One more thing you should configure properly is the languages you want Duet AI to support, which can be reached in the Google Cloud Code/Duet AI settings as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/03duet-ai-settings-link.jpg" title="Duet AI (Cloud Code) settings on VS Code" alt="Duet AI (Cloud Code) settings on VS Code" />
<p>Then change the settings to include the programming languages you want Duet AI to support, you will find it after scrolling down a bit and you might need to add the languages of your choice:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/04duet-ai-settings-languages.jpg" title="Duet AI (Cloud Code) languages list on VS Code" alt="Duet AI (Cloud Code) languages list on VS Code" />
<p>Then you are good to go. In the next section, you will learn how to write a simple Node.js API with Duet AI on VS Code.</p>
<h2 id="writing-a-simple-node.js-api-with-duet-ai" tabindex="-1">Writing a simple Node.js API with Duet AI <a class="direct-link" href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#writing-a-simple-node.js-api-with-duet-ai">#</a></h2>
<p>You can either start a new project on your own or clone this open-source GitHub <a href="https://github.com/geshan/nodejs-duet-ai">repository</a> by running:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone git@github.com:geshan/nodejs-duet-ai.git</code></pre>
<p>After the repository is cloned, you can go into it with <code>cd nodejs-duet-ai</code> and open it in VS Code. Let's try to initialize the repository with NPM and install Express.js.</p>
<p>To do this, you can ask Duet AI to help you with the following prompt:</p>
<pre><code>How do I initialize a Node.js project with NPM?
</code></pre>
<p>That resulted in:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/05duet-ai-npm-init.jpg" title="Duet AI (Cloud Code) on VS Code helping to initialize a Node.js project with NPM" alt="Duet AI (Cloud Code) on VS Code helping to initialize a Node.js project with NPM" />
<p>It gave out the instructions to initialize the project with NPM and also how to add Express.js to the project, as seen above. But, to keep things simple you can run <code>npm init -y</code> to just get the <code>package.json</code> file set up as I have done above.</p>
<p>As the next step, you will install <a href="https://expressjs.com/">Express</a> framework to this project. You can ask Duet AI to help you with the following prompt:</p>
<pre><code>How do I install and save Express.js to the package.json file?
</code></pre>
<p>It came back with good instructions but not that great as the <code>dependencies</code> part was not there in the <code>package.json</code> file.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/06duet-ai-express.jpg" title="Duet AI (Cloud Code) on VS Code helping to add Express.js to a Node.js project" alt="Duet AI (Cloud Code) on VS Code helping to add Express.js to a Node.js project" />
<p>Even though the suggestion was good but not right for the scenario. So you can run <code>npm install --save express</code> to install express as well as add it to the <code>package.json</code> file, as seen in the above screenshot.</p>
<p>One thing to notice here (which will be true for most/all AI assistants) is, that they can give you a first draft (v1) which kind of works.</p>
<blockquote>
<p>You as the software engineer will need to improvise on the given solution to make it work. Then you will also have to optimize it for performance and scalability.</p>
</blockquote>
<p>You can also follow this <a href="https://geshan.com.np/blog/2021/05/nodejs-express-tutorial/">Node.js Express</a> step-by-step tutorial if you like to create a 1 page Node.js Express application. I also created a <code>index.js</code> file with a basic Node.js Express server running on port 8080 copying and changing the code given by Duet AI. The <code>index.js</code> looks like the below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> port <span class="token operator">=</span> <span class="token number">8080</span> <span class="token operator">||</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">PORT</span><span class="token punctuation">;</span><br /><br />app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>port<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Server listening on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>At this point, you want to add an "OK" route to your Node.js Express application. You can ask Duet AI to help you with the following prompt:</p>
<pre><code>how do I add an ok route to express.js?
</code></pre>
<p>It replied with the following which is useable this time, I added it as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/07duet-ai-express-route.jpg" title="Duet AI (Cloud Code) on VS Code helping to add Express.js route" alt="Duet AI (Cloud Code) on VS Code helping to add Express.js route" />
<p>After that, while adding the route it had a suggestion too:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/08duet-ai-express-suggest.jpg" title="Duet AI (Cloud Code) on VS Code suggesting a new route" alt="Duet AI (Cloud Code) on VS Code suggesting a new route" />
<p>Then you can run the server and see the <code>ok</code> route is working as expected by running <code>node index.js</code>. It will look as follows on your browser: <code>http://localhost:8080/</code>:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/09express-running-02.jpg" title="Express running on port 8080" alt="Express running on port 8080" />
<p>Now it is time to add a dummy JSON response, so you can ask Duet AI to help you with the following prompt:</p>
<pre><code>How can I GET Route with Express.js that returns some blog posts as JSON?
</code></pre>
<p>That resulted in:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/10duet-ai-dummy-json.jpg" title="Duet AI (Cloud Code) on VS Code suggesting a new route with JSON response for posts" alt="Duet AI (Cloud Code) on VS Code suggesting a new route with JSON response for posts" />
<p>You can copy and paste that suggestion to your <code>index.js</code> file and run the server again. You can see the dummy JSON response for posts at <code>http://localhost:8000/posts</code> as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/11express-posts-json.jpg" title="Express running on port 8080 with posts JSON" alt="Express running on port 8080 with posts JSON" />
<p>Now you have the basic Node.js API running locally with much help from Duet AI. In the next section, you will learn how to deploy this Node.js API on Google Cloud Run from VS Code using Duet AI.</p>
<h2 id="deploy-to-cloud-run-with-duet-ai" tabindex="-1">Deploy to cloud run with Duet AI <a class="direct-link" href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#deploy-to-cloud-run-with-duet-ai">#</a></h2>
<p>To deploy your app to Google Cloud Run, you will need to create a Dockerfile. You can ask Duet AI to help you with this too. Type in the following prompt to get some assistance:</p>
<pre><code>Can you give me an optimized dockerfile for this Node.js Express project?
</code></pre>
<p>Duet AI came back with the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/12duet-ai-dockerfile.jpg" title="Duet AI suggesting a Dockerfile for a Node.js app" alt="Duet AI suggesting a Dockerfile for a Node.js app" />
<p>So you can copy the suggested code and create a file named <code>dockerfile</code> in the root of your project like the below:</p>
<pre><code>FROM node:16-slim
EXPOSE 8080
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . ./
CMD [ "npm", "start" ]
</code></pre>
<p>This <code>dockerfile</code> can be made better by implementing multiple things like using Node version 20 the latest LTS as well as using a <a href="https://geshan.com.np/blog/2019/11/how-to-use-docker-multi-stage-build/">multi-stage build</a>. But for now we are going to use this dockerfile with just one line added <code>EXPOSE 8080</code> to make it work with Google Cloud Run.</p>
<p>You can test the Dockerfile by running <code>docker build -t node-app .</code> but we will deploy this to Google Cloud Run next. Duet AI as Google Cloud Run support built into it, you can read more about <a href="https://geshan.com.np/blog/2023/04/serverless-containers/">serverless containers</a> if you like.</p>
<p>If you open your VS Code command palette and type <code>cloud run</code>, you will see:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/13duet-ai-cloud-run.jpg" title="Duet AI integrated with Cloud Run" alt="Duet AI integrated with Cloud Run" />
<p>When you select that you can deploy your current source code directly to Google Cloud Run without leaving your editor (VS Code). It will take you to the settings page like below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/14duet-ai-cloud-run-settings-01.jpg" title="Duet AI integrated with Cloud Run service settings" alt="Duet AI integrated with Cloud Run service settings" />
<p>In this settings section for Cloud Run, you can set the name of the service (which will take the name of the folder by default), then you can also select the region. After that you can specify the authentication, as you want it to be public the "Allow unauthenticated invocations" is selected. These settings are similar to <a href="https://cloud.google.com/run/docs/deploying">deploying</a> a Cloud Run service from the Google Cloud Console interface.</p>
<p>When you scroll down you will see more settings as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/15duet-ai-cloud-run-settings-02.jpg" title="Duet AI integrated with Cloud Run service settings for building" alt="Duet AI integrated with Cloud Run service settings for building" />
<p>In this part, you will specify the revision setting and more importantly you will select <code>Cloud Build</code> to build your dockerfile on Google <a href="https://cloud.google.com/build">Cloud Build</a> not your local. This will also push the container to the artifact repository automatically.</p>
<p>After that at the end, you will find the <code>Deploy</code> button to deploy your service to Google Cloud Run.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/16duet-ai-cloud-run-settings-03.jpg" title="Duet AI integrated with Cloud Run service settings for using Dockerfile" alt="Duet AI integrated with Cloud Run service settings for using Dockerfile" />
<p>The settings selected here for using Docker and dockerfile are correct. You could also use <code>cloudbuild.yaml</code> file but that is out of scope for this post. Next, you can click "Deploy" to deploy your service to Google Cloud Run. That will lead to:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/17duet-ai-cloud-run-deploying.jpg" title="Duet AI deploying Node.js service to Cloud Run" alt="Duet AI deploying Node.js service to Cloud Run" />
<p>You can view detailed logs by clicing <code>Show detailed logs</code>, which will show you something like:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/18duet-ai-cloud-run-logs.jpg" title="Duet AI deploying Node.js service to Cloud Run logs" alt="Duet AI deploying Node.js service to Cloud Run logs" />
<p>As you had selected the build to run on Cloud Build, you can see the process run on Cloud Build in some time like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/19cloud-build.jpg" title="Docker build and push on Cloud Build from Duet AI" alt="Docker build and push on Cloud Build from Duet AI" />
<p>It will take some minutes for the whole process to finish, if all of it goes fine you will see a URL where your service will be running on Google Cloud run as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/20cloud-run-deployed.jpg" title="App deployed on Cloud Run with Duet AI" alt="App deployed on Cloud Run with Duet AI" />
<p>Then, you can visit that <code>URL/posts</code> to see if the app is running properly, and you should be able to see:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/21cloud-run-ok.jpg" title="App deployed on Cloud Run with Duet AI and running well" alt="App deployed on Cloud Run with Duet AI and running well" />
<p>You can also check the Cloud Run stats on the service page as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nodejs-duet-ai-vs-code/22cloud-run-stats.jpg" title="App deployed on Cloud Run with Duet AI and running well with stats" alt="App deployed on Cloud Run with Duet AI and running well with stats" />
<p>There you have it, a way to develop a very simple Node.js API with Duet AI. Then you can deploy the app to Cloud Run without leaving your editor/IDE.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/12/nodejs-duet-ai-vs-code/#conclusion">#</a></h2>
<p>In this post, you learned the basics of Duet AI to create your Node.js API and deploy it on Google Cloud Run. As you have seen Duet AI is very useful for software engineers. It enhances your coding experience and simplifies deployment too.</p>
<blockquote>
<p>By working alongside Duet AI, you can streamline your development workflow, focus on innovation, and bring your ideas to life faster than ever before.</p>
</blockquote>
<p>So, go ahead, give Duet AI a try, and let your AI teammate take care of the heavy lifting while you code with confidence!</p>
<p>Duet AI also offers additional features like code explanations, refactoring suggestions, and security recommendations. Explore these functionalities to unlock even more potential from your sidekick, Keep exploring!</p>
Jest mock implementation: A beginner’s guide to replacing function implementation for tests2023-11-25T11:43:54Zhttps://geshan.com.np/blog/2023/11/jest-mockimplementation/<p>Jest Mock Implementation is a technique that lets you replace the internal logic of a function with a custom implementation during test execution. This can be immensely helpful in scenarios where you want to isolate a specific piece of code for testing without affecting the behavior of other components. In this blog post, you will learn how to use Jest Mock Implementation and how to leverage it effectively. Let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/jest-mockimplementation/01jest-mockimplementation.jpg" title="Jest mock implementation: A beginner’s guide to replacing function implementation for tests" alt="Jest mock implementation: A beginner’s guide to replacing function implementation for tests" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#jest-mock-implementation-an-intro">Jest Mock implementation an intro</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#when-to-use-jest-mockimlementation">When to use Jest mockImlementation</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#how-to-use-mockimplementation-with-jest">How to use mockImplementation with Jest</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#example-with-process-exit-and-console">Example with Process exit and console</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#tests-using-jest-mockimplenentation">Tests using Jest mockImplenentation.</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#conclusion">Conclusion</a></li>
</ul>
<h2 id="jest-mock-implementation-an-intro" tabindex="-1">Jest Mock implementation an intro <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#jest-mock-implementation-an-intro">#</a></h2>
<p><a href="https://jestjs.io/docs/mock-function-api#mockfnmockimplementationfn">Jest mockImplementation</a> enables developers to replace the original implementation of a function with a mock function, allowing them to control the function's behavior and verify specific interactions. This technique proves particularly beneficial when testing code that interacts with external dependencies, such as APIs, databases, or filesystem operations.</p>
<p>Jest mockIementaiton accepts a function that will replace the real implementation. You can also use <a href="https://jestjs.io/docs/mock-function-api#mockfnmockimplementationoncefn">Jest mockimplemantationOnce</a> to only mock the implementation once. For example, if the same function is called three times you can call <code>mockFn.mockImplemenationOnce</code> two times to get the mock result and the last call and execute the real function. You will see this in the example in the later section. In the next part, you will learn when to use Jest mockImplementaiton.</p>
<h2 id="when-to-use-jest-mockimlementation" tabindex="-1">When to use Jest mockImlementation <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#when-to-use-jest-mockimlementation">#</a></h2>
<p>Jest mockImplementation can be used in multiple scenarios, it is especially useful when used with <a href="https://www.meticulous.ai/blog/how-to-use-jest-spyon">Jest spyOn</a>. Still, there are other useful scenarios when mockImplementation can be used.</p>
<p>Without going into much detail, Jest mockImplentation is practical when you want to mock and test internal or external dependencies (like Axios), simulate error conditions, and test for the specific error case (like an API returning a 404 for instance). It is also handy to control the function output as needed and also isolate the system under test. In the next section, you will learn about how to use Jest mockImplenentation and Jest mockImplementationOnce with an example script that guesses Nationality from a given name.</p>
<h2 id="how-to-use-mockimplementation-with-jest" tabindex="-1">How to use mockImplementation with Jest <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#how-to-use-mockimplementation-with-jest">#</a></h2>
<p>As mentioned there are multiple use cases of Jest mockImplemenation. It can be used to do basic mocking, mocking modules, mocking promises, etc. For this tutorial, you will see a simple yet useful example where given a name the script will guess the nationalities of the name with a probability percentage.</p>
<p>To achieve this, you will use the <a href="https://nationalize.io/#overview">Nationalize.io API</a> to send in the name and get back the percent probability of the nationalities. Technically you will use Node.js 20.x (to use top level await) and utilize the <a href="https://axios-http.com/">Axios</a> library to make the HTTP calls and of course, <a href="https://jestjs.io/">Jest</a> for unit testing. Let’s go ahead!</p>
<h3 id="example-with-process-exit-and-console" tabindex="-1">Example with Process exit and console <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#example-with-process-exit-and-console">#</a></h3>
<p>Below is the example script (<a href="https://github.com/geshan/jest-mockImplementation/blob/master/src/nationalityGuesser.js">src/nationalityGuesser.js</a>) that does the main work, you can see the full code in this open-source <a href="https://github.com/geshan/jest-mockImplementation">GitHub repository</a>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">guessNationalities</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.nationalize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> hasCountryData <span class="token operator">=</span> response<span class="token operator">?.</span>data<span class="token operator">?.</span>country <span class="token operator">&&</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length<span class="token punctuation">;</span><br /><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Nationalities for the name </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> are: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>hasCountryData <span class="token operator">?</span> response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>country<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">c</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>c<span class="token punctuation">.</span>country_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>c<span class="token punctuation">.</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">', '</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">'none'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Done!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error occurred: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token punctuation">.</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> err<span class="token punctuation">.</span>stack<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>It is a simple script that imports Axios, then in the async function called <code>guessNationalites</code> takes in the name to guess the nationalities for. After that in the try block it sends a request to the Nationalize API with the name and if the country data is received loops through it and shows the output in the console. Then it also console logs <code>Done!</code>.</p>
<p>In case of any error, it will jump to the catch section and log the error then exit the process with an exit code of 1. By default for successful execution, the <a href="https://www.cyberciti.biz/faq/linux-bash-exit-status-set-exit-statusin-bash/">exit code</a> is 0. This is how it looks like when executed with the name <code>john</code>.</p>
<img class="center" src="https://geshan.com.np/images/jest-mockimplementation/02jest-mockimplementation-run.jpg" title="Jest mock implementation example run for name and nationalities guesser script" alt="Jest mock implementation example run for name and nationalities guesser script" />
<p>So the API responds with <code>john</code> is 7.5% Irish, 5.5% Kenyan, 4.9% British and other nationalities. Next you will learn about the test for the above script.</p>
<h3 id="tests-using-jest-mockimplenentation." tabindex="-1">Tests using Jest mockImplenentation. <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#tests-using-jest-mockimplenentation.">#</a></h3>
<p>You can write test (<a href="https://github.com/geshan/jest-mockImplementation/blob/master/test/nationalityGuesser.spec.js">tests/nationalityGuesser.spec.js</a>) for the above file which will look like the below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> guessNationalities <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../src/nationalityGuesser.js'</span><span class="token punctuation">;</span><br /><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><br />jest<span class="token punctuation">.</span><span class="token function">mock</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'guessNationalities'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> jest<span class="token punctuation">.</span><span class="token function">resetAllMocks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token comment">//without the above reset, in the second test it will take axios.get as the second call</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'should return the nationality based on the name'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token string">'john'</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> consoleLog <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">spyOn</span><span class="token punctuation">(</span>console<span class="token punctuation">,</span> <span class="token string">"log"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mockImplementationOnce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> axios<span class="token punctuation">.</span>get<span class="token punctuation">.</span><span class="token function">mockResolvedValue</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">2346926</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'john'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">country</span><span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">country_id</span><span class="token operator">:</span> <span class="token string">'IE'</span><span class="token punctuation">,</span> <span class="token literal-property property">probability</span><span class="token operator">:</span> <span class="token number">0.075</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">country_id</span><span class="token operator">:</span> <span class="token string">'KE'</span><span class="token punctuation">,</span> <span class="token literal-property property">probability</span><span class="token operator">:</span> <span class="token number">0.055</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">country_id</span><span class="token operator">:</span> <span class="token string">'GB'</span><span class="token punctuation">,</span> <span class="token literal-property property">probability</span><span class="token operator">:</span> <span class="token number">0.049</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">country_id</span><span class="token operator">:</span> <span class="token string">'PH'</span><span class="token punctuation">,</span> <span class="token literal-property property">probability</span><span class="token operator">:</span> <span class="token number">0.045</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">country_id</span><span class="token operator">:</span> <span class="token string">'AU'</span><span class="token punctuation">,</span> <span class="token literal-property property">probability</span><span class="token operator">:</span> <span class="token number">0.045</span> <span class="token punctuation">}</span><br /> <span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">await</span> <span class="token function">guessNationalities</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>axios<span class="token punctuation">.</span>get<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>axios<span class="token punctuation">.</span>get<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token string">'https://api.nationalize.io/?name=john'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token function">expect</span><span class="token punctuation">(</span>consoleLog<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>consoleLog<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenNthCalledWith</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">'Nationalities for the name john are: IE - 7.5%, KE - 5.5%, GB - 4.9%, PH - 4.5%, AU - 4.5%'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>consoleLog<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenNthCalledWith</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">'Done!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'should handle errors and exit gracefully'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token string">'error'</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">const</span> processExit <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">spyOn</span><span class="token punctuation">(</span>process<span class="token punctuation">,</span> <span class="token string">'exit'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mockImplementation</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> consoleError <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">spyOn</span><span class="token punctuation">(</span>console<span class="token punctuation">,</span> <span class="token string">'error'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mockImplementation</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> axios<span class="token punctuation">.</span>get<span class="token punctuation">.</span><span class="token function">mockRejectedValue</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'API error'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">await</span> <span class="token function">guessNationalities</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token function">expect</span><span class="token punctuation">(</span>axios<span class="token punctuation">.</span>get<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>axios<span class="token punctuation">.</span>get<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token string">'https://api.nationalize.io/?name=error'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>consoleError<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>consoleError<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token string">'Error occurred: API error'</span><span class="token punctuation">,</span> expect<span class="token punctuation">.</span><span class="token function">any</span><span class="token punctuation">(</span>String<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>processExit<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">expect</span><span class="token punctuation">(</span>processExit<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let's understand what the test is doing and how Jest mockImlementation is crucial to it. First, you import the module to test that is <code>nationalityGuesser</code>. Then you import axios and in the next line mock the whole <a href="https://jestjs.io/docs/mock-functions#mocking-modules">module</a>.</p>
<p>Consequently, you start the <code>describe</code> part of the test with the name of the module under test. After that, you add the <a href="https://geshan.com.np/blog/2022/06/jest-beforeeach/">Jest beforeEach</a> which as the name suggests runs before each test. Here, you call the <code>jest.ResetAllMocks()</code> to reset the mocks for each test so that older calls made for previous tests do not affect the current test.</p>
<p>Next, you write the first test that checks <code>should return the nationality based on the name</code> which is an async function as await will be used in that test. You set the name to test to be <code>john</code>, then spy on the <code>console.log</code> method, you add the <code>mockImplentationOnce</code> which only mocks the first call to <code>console.log</code> the subsequent calls will work as usual and print the message on the real console. This is seen later when you run the test.</p>
<p>After that, you add a mock response from nationalize API for the name <code>john</code> in the <code>mockResolvedValue</code> of <code>axios.get</code> call. Till this point it is the Arrange part of the <a href="https://automationpanda.com/2020/07/07/arrange-act-assert-a-pattern-for-writing-good-tests/">Arrange Act Assert</a> pattern followed for good unit tests.</p>
<p>Then, you call the <code>guessNationalities</code> function passing <code>john</code> with an await. After the act, the asserts start next. First, you assert that <code>axios.get</code> is called once and is called with the right string. For this you use <a href="https://geshan.com.np/blog/2022/07/jest-tohavebeencalledwith/">Jest toHaveBeenCalledWith</a> and make sure the right URL of <code>https://api.nationalize.io/?name=john</code> is sent to <code>axios.get</code>. Subsequently, you make sure that the <code>console.log</code> is called twice and also check that the parameters passed to it on both occasions are as expected.</p>
<p>You can also run a <a href="https://geshan.com.np/blog/2022/07/jest-run-single-test/">single test with jest</a> using the <code>-t</code> flag like:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> t -- <span class="token parameter variable">-t</span> <span class="token string">'should return the nationality based on the name'</span></code></pre>
<p>It will run only the first test and skip the second one as seen below:</p>
<img class="center" src="https://geshan.com.np/images/jest-mockimplementation/03jest-mockimplementation-single-test-run.jpg" title="Jest mock implementation run single jest test" alt="Jest mock implementation run single jest test" />
<p>There is one more thing to put careful consideration here, the console shows <code>Done!</code> but it does not show the <code>Nationalities for the name john…</code> line. It is because of the line:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> consoleLog <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">spyOn</span><span class="token punctuation">(</span>console<span class="token punctuation">,</span> <span class="token string">"log"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mockImplementationOnce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Due to this the first call to <code>console.log</code> was mocked but the second call was not mocked resulting in printing the <code>Done!</code> on the screen.</p>
<p>Next, you have added a test titled <code>should handle errors and exit gracefully</code>. In this test the most interesting part is mocking the <code>process.exit</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> processExit <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">spyOn</span><span class="token punctuation">(</span>process<span class="token punctuation">,</span> <span class="token string">'exit'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mockImplementation</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If you do not do this, it will exit the <code>jest</code> process and not run the test fully. With this important mock implementation the <code>process.exit</code> does nothing, which means the <code>jest</code> process completes the test. You can run your test with <code>npm test</code> or <code>npm t</code> on the root of the project. Which looks like the below:</p>
<img class="center" src="https://geshan.com.np/images/jest-mockimplementation/04jest-mockimplementation-test-run.jpg" title="Jest mock implementation run all jest test" alt="Jest mock implementation run all jest tests" />
<p>The other mocks and assertions in this second test are the same as the above one. In place of the <code>console.log</code> it mocks the <code>console.error</code> as this test case only has an error call and no log calls. If you want to get the code coverage you can run <code>npm run test:cov</code>. There you have it, now you know how to use both <code>mockImplementation</code> and <code>mockImplementationOnce</code> with Jest tests.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/11/jest-mockimplementation/#conclusion">#</a></h2>
<p>Jest Mock Implementation is a powerful tool that enhances the effectiveness of your tests by allowing you to control and isolate specific parts of your code. Knowing when and how to use Jest Mock Implementation is crucial for writing repeatable and reliable tests. By replacing original function implementations with mock functions, developers can verify specific interactions, simulate error conditions, and effectively test code that interacts with external dependencies.</p>
<p>In this tutorial, you learned what Jest mock implementation is and when to use it. Then you witnessed a full example of how to use it with a script that guesses Nationalities for a given name. Whether you're a seasoned developer or a beginner, mastering Jest mockImplementation will significantly enhance your testing capabilities and contribute to the creation of high-quality software. Keep testing! 🚀</p>
How to use Axios with Typescript a beginner’s guide2023-11-07T11:43:57Zhttps://geshan.com.np/blog/2023/11/axios-typescript/<p>Axios is one of the most popular HTTP client libraries for making requests to REST APIs in JavaScript and TypeScript applications. In this beginner's guide, you will learn at how to set up and use Axios with any TypeScript project to make API requests and get response data. Let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/axios-typescript/01axios-typescript.jpg" title="How to use Axios with Typescript a beginner’s guide" alt="How to use Axios with Typescript a beginner’s guide" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/11/axios-typescript/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/11/axios-typescript/#axios-introduction">Axios introduction</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/axios-typescript/#how-to-set-up-axios-with-typescript">How to set up Axios with TypeScript</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/axios-typescript/#axios-typescript-example---most-followed-user-on-github">Axios TypeScript example - most followed user on GitHub</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/axios-typescript/#axios-post-example-with-typescirpt">Axios POST example with TypeScirpt</a></li>
<li><a href="https://geshan.com.np/blog/2023/11/axios-typescript/#conclusion">Conclusion</a></li>
</ul>
<h2 id="axios-introduction" tabindex="-1">Axios introduction <a class="direct-link" href="https://geshan.com.np/blog/2023/11/axios-typescript/#axios-introduction">#</a></h2>
<p><a href="https://axios-http.com/docs/intro">Axios</a> is a promise-based HTTP client for JavaScript that allows us to make requests to REST endpoints. It is isomorphic, meaning it can run in the browser and Node.js too. On the server-side it uses the native node.js HTTP module, while on the client (browser) it uses XMLHttpRequest.</p>
<p>Some key features of Axios include:</p>
<ul>
<li>Make XMLHttpRequests from the browser and Node.js</li>
<li>Intercept requests and responses with <a href="https://geshan.com.np/blog/2022/12/axios-interceptors/">Axios interceptors</a></li>
<li>Transform request and response data</li>
<li>Automatically convert JSON data</li>
<li>Client side support for protecting against XSRF</li>
</ul>
<p>Compared to the native <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">fetch API</a> in JavaScript, Axios provides a simpler API and has built-in support for some commonly needed functionality like transforming JSON data. You can use <a href="https://geshan.com.np/blog/2023/09/axios-retry/">Axios retry</a> to retry failed requests with custom configuration. If you utilize <a href="https://geshan.com.np/blog/2022/11/axios-timeout/">timeouts with Axios</a> it will make your application more efficient.</p>
<p>Overall, Axios takes a lot of the complexity out of making HTTP requests and handling responses. It simplifies app code and reduces the need for boilerplate request/response handling logic. As per NPM trends (excluding Node fetch as fetch is part of Node core now), Axios is the <a href="https://npmtrends.com/axios-vs-got-vs-request-vs-superagent">most popular</a> HTTP library with over 35 million weekly downloads which is greater than all 3 competitors (Got, Request, Superagent) combined. In the next, section you will get your hands dirty with code.</p>
<h2 id="how-to-set-up-axios-with-typescript" tabindex="-1">How to set up Axios with TypeScript <a class="direct-link" href="https://geshan.com.np/blog/2023/11/axios-typescript/#how-to-set-up-axios-with-typescript">#</a></h2>
<p>Before you begin to install Axios in a Typescript project, you will need Node.js installed locally. For this tutorial, Node 20.x is used with Typescript 5.1. If you want a starting point with a bare-minimum TypeScript set up clone the example code repository in the <code>nvm-20</code> branch with the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone <span class="token parameter variable">-b</span> nvm-20 git@github.com:geshan/axios-typescript.git</code></pre>
<p>Now if you go into the directory with <code>cd axios-typescript</code> you can run the command below to install Axios (it is v 1.6 at the time of writing):</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> axios</code></pre>
<p>Now you can use Axios in your TypeScript project. In the next section, you will use Axios to find out who is the most followed user on GitHub using Axios.</p>
<h2 id="axios-typescript-example---most-followed-user-on-github" tabindex="-1">Axios TypeScript example - most followed user on GitHub <a class="direct-link" href="https://geshan.com.np/blog/2023/11/axios-typescript/#axios-typescript-example---most-followed-user-on-github">#</a></h2>
<p>For this example, you will try to find out who is the most followed user on GitHub. For this you will need to call two GitHub APIs, the first one search for users with more than 60K followers and sort by followers. Then with the result pick the first user (as it is sorted by followers) and get the user from the get user API of GitHub.</p>
<p>You will do all the above using Axios in a TypeScript project and the code can be saved in <code>src/index.ts</code> file. The contents of the <a href="https://github.com/geshan/axios-typescript/blob/master/src/index.ts">file</a> will look like the below:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> axios<span class="token punctuation">,</span> <span class="token punctuation">{</span> AxiosResponse<span class="token punctuation">,</span> AxiosRequestConfig<span class="token punctuation">,</span> RawAxiosRequestHeaders <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> client <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> baseURL<span class="token operator">:</span> <span class="token string">'https://api.github.com'</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">type</span> <span class="token class-name">githubFoundUser</span> <span class="token operator">=</span> <span class="token punctuation">{</span><br /> login<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span><br /> id<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">type</span> <span class="token class-name">githubUser</span> <span class="token operator">=</span> <span class="token punctuation">{</span><br /> login<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span><br /> id<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><br /> followers<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> config<span class="token operator">:</span> AxiosRequestConfig <span class="token operator">=</span> <span class="token punctuation">{</span><br /> headers<span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">'Accept'</span><span class="token operator">:</span> <span class="token string">'application/vnd.github+json'</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span> <span class="token keyword">as</span> RawAxiosRequestHeaders<span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> queryString<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">q=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span><span class="token string">'followers:>=60000'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&sort=followers&order=desc</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> searchResponse<span class="token operator">:</span> AxiosResponse <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/search/users?</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>queryString<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> foundUsers<span class="token operator">:</span> githubFoundUser<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> searchResponse<span class="token punctuation">.</span>data<span class="token punctuation">.</span>items<span class="token punctuation">;</span><br /><br /> <span class="token keyword">const</span> username<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">=</span> foundUsers<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>login<span class="token punctuation">;</span><br /> <span class="token keyword">const</span> userResponse<span class="token operator">:</span> AxiosResponse <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> user<span class="token operator">:</span> githubUser <span class="token operator">=</span> userResponse<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /> <span class="token keyword">const</span> followersCount <span class="token operator">=</span> user<span class="token punctuation">.</span>followers<span class="token punctuation">;</span><br /><br /> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The most followed user on GitHub is "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">" with </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>followersCount<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> followers.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let’s go through the main points to note in this Axios TypeScirpt example with GitHub API calls:</p>
<ul>
<li>You create a client with <code>axios.create</code> giving it the base URL of the GitHub API</li>
<li>Then you define two types, as it is TypeScirpt one for found GitHub users and the next one for a GitHub user.</li>
<li>After that, you define an async Immediately Invoked Function Expression a.k.a <a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIFE</a> so that the code executes when the file runs and await can be used. Another way to do it can be with <a href="https://www.stefanjudis.com/today-i-learned/top-level-await-is-available-in-node-js-modules/">top-level await</a>.</li>
<li>In this IIFE, you define an Axios config with a header of <code>'Accept': 'application/vnd.github+json'</code> which is <a href="https://docs.github.com/en/rest/overview/media-types?apiVersion=2022-11-28">recommended</a> in the GitHub API docs.</li>
<li>Following that you construct a query string to search users that have more than 60K followers sorted by most followers first and in the try the GET request to find those users. (<a href="https://github.com/search?q=followers%3A%3E%3D60000&type=Users">9 users</a> are found at the time of writing)</li>
<li>Next you assign the returned <code>items</code> in <code>foundUsers</code> as an array of <code>githubFoundUsers</code> type</li>
<li>Then you get the username of the first user (which should be <code>travolds</code> at the time of writing)</li>
<li>The second get request is fired with the first user’s username (to get the followers count) and the response’s data is assigned to the user const of type <code>githubUser</code>.</li>
<li>After that user’s number of followers is assigned to <code>followersCount</code> const.</li>
<li>The message of the most followed user on GitHub is logged after that.</li>
<li>In case of any error that is logged too as the whole code is in a try-catch block.</li>
</ul>
<p>The output of the above code looks like the below when run with <code>npx ts-node src/index.ts</code></p>
<pre><code>The most followed user on GitHub is "torvalds" with 193729 followers.
</code></pre>
<p>So the most followed user on Github is Linus Travolds the creator of Linux with 193.7K followers. With this simple but useful example, you have the core knowledge of how to use Axios with TypeScript. In the next section, you will learn how to do a POST with Axios and TypeScirpt.</p>
<h3 id="axios-post-example-with-typescirpt" tabindex="-1">Axios POST example with TypeScirpt <a class="direct-link" href="https://geshan.com.np/blog/2023/11/axios-typescript/#axios-post-example-with-typescirpt">#</a></h3>
<p>You can make other calls with Axios and Typescript in addition to a GET call. Below is an example of a POST call on HTTPbin where it will send back the same data sent in the POST body. You can save the file in <code>src/post.ts</code> file with the following contents:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> axios<span class="token punctuation">,</span> <span class="token punctuation">{</span> AxiosResponse<span class="token punctuation">,</span> AxiosRequestConfig<span class="token punctuation">,</span> RawAxiosRequestHeaders <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> client <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> baseURL<span class="token operator">:</span> <span class="token string">'https://httpbin.org'</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> config<span class="token operator">:</span> AxiosRequestConfig <span class="token operator">=</span> <span class="token punctuation">{</span><br /> headers<span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">'Accept'</span><span class="token operator">:</span> <span class="token string">'application/json'</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span> <span class="token keyword">as</span> RawAxiosRequestHeaders<span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string-property property">'message'</span><span class="token operator">:</span> <span class="token string">'Hello World!'</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> response<span class="token operator">:</span> AxiosResponse <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/post</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> data <span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>status<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>data<span class="token punctuation">.</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span> <br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let’s go through the main points to note in the above code.</p>
<p>Most things are similar to the above example. The main difference is in the lines:</p>
<pre class="language-ts"><code class="language-ts"> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string-property property">'message'</span><span class="token operator">:</span> <span class="token string">'Hello World!'</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> response<span class="token operator">:</span> AxiosResponse <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/post</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> data <span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>An HTTP POST call is made here and the data with a message of <code>Hello World!</code> is passed to the HTTP Bin API. The third parameter is the config which is adding a header with accept JSON. The output of the above code when run with <code>npx ts-node src/post.ts</code> look like the below:</p>
<pre class="language-bash"><code class="language-bash"><span class="token number">200</span> <br /><span class="token punctuation">{</span> message: <span class="token string">'Hello World!'</span> <span class="token punctuation">}</span></code></pre>
<p>If you want to compile TypeScript to JavaScript you can add the following to the <code>scripts</code> sections of your <code>package.json</code> file:</p>
<pre class="language-js"><code class="language-js"> <span class="token string-property property">"build"</span><span class="token operator">:</span> <span class="token string">"tsc -p tsconfig.json"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"start"</span><span class="token operator">:</span> <span class="token string">"node dist/index.js"</span><span class="token punctuation">,</span></code></pre>
<p>Then you can run <code>npm run build && npm start</code> to see the output of the first example. You can find all the code for your reference in this <a href="https://github.com/geshan/axios-typescript/">GitHub repository</a>.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/11/axios-typescript/#conclusion">#</a></h2>
<p>That covers the basics of using Axios with TypeScript to make API calls and handle the response data. You have learned the basics of Axios and its types for making a GET and a POST call in a TypeScript environment. The example is executed on a Node.js environment but it should work the same on a browser too as Axios runs on both the server and the client. I hope you have learned the core and important knowledge of using Axios and TypeScript together, keep coding! 🚀</p>
How to use the string_agg function in Postgres with examples2023-10-27T11:52:57Zhttps://geshan.com.np/blog/2023/10/postgres-string_agg/<p>Are you a software engineer who works with PostgreSQL? Do you often find yourself needing to manipulate and aggregate strings in your database? If so, you're in luck because PostgreSQL provides a powerful function called string_agg. In this blog post, you dive into what string_agg is, how it's related to MySQL's group_concat, and walk through a couple of examples using real data. By the end, you'll have a solid understanding of how to make the most string_agg in your PostgreSQL queries. Let’s get going!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/postgres-string_agg/01postgres-string_agg.jpg" title="How to use the string_agg function in Postgres with examples" alt="How to use the string_agg function in Postgres with examples" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#postgres-string-agg">Postgres string_agg</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#related-to-mysql-group-concat">Related to MySQL group_concat</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#example-of-billionaires-data">Example of billionaires data</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#list-the-billionaires-by-country-and-birth-year-with-count-per-country">List the billionaires by country and birth year with count per country</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#list-the-billionaires-by-category-and-count-per-category">List the billionaires by category and count per category</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#conclusion">Conclusion</a></li>
</ul>
<h2 id="postgres-string_agg" tabindex="-1">Postgres string_agg <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#postgres-string_agg">#</a></h2>
<p>Postgres string_agg is an <a href="https://www.postgresql.org/docs/9.0/functions-aggregate.html">aggregate function</a> that allows you to concatenate values from multiple rows into a single string. It is particularly useful when dealing with string aggregation or concatenation in a SQL query. This function can be applied to columns of text, varchar, or other string types. The basic syntax of string_agg is as follows:</p>
<pre class="language-sql"><code class="language-sql">string_agg<span class="token punctuation">(</span>expression<span class="token punctuation">,</span> <span class="token keyword">delimiter</span><span class="token punctuation">)</span></code></pre>
<p>The two parts are expression and delimeter:</p>
<ul>
<li>expression: The expression or column you want to concatenate.</li>
<li>delimiter: The separator that will be inserted between the concatenated values.</li>
</ul>
<p>For instance, you have customers in multiple countries, and for a campaign, you want to send emails to them. The need is to get all the customer emails grouped by country it can be done with a query that looks like the below:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> country<span class="token punctuation">.</span>name<span class="token punctuation">,</span> string_agg<span class="token punctuation">(</span>customer<span class="token punctuation">.</span>email<span class="token punctuation">,</span> ‘<span class="token punctuation">,</span> ’<span class="token punctuation">)</span><br /><span class="token keyword">FROM</span> customer <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> country <span class="token keyword">ON</span> customer<span class="token punctuation">.</span>country_id <span class="token operator">=</span> country<span class="token punctuation">.</span>id <br /><span class="token keyword">GROUP</span> <span class="token keyword">By</span> country<span class="token punctuation">.</span>name</code></pre>
<h2 id="related-to-mysql-group_concat" tabindex="-1">Related to MySQL group_concat <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#related-to-mysql-group_concat">#</a></h2>
<p>If you're familiar with MySQL, you might have used the <a href="https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat">group_concat</a> function. string_agg in Postgres serves a similar purpose as group_concat in MySQL. They both allow you to aggregate and concatenate values from multiple rows into a single string. However, there are some syntax and implementation differences between the two.</p>
<p>Below is an example of the usage of group_concat taken directly form the MySQL docs:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> student_name<span class="token punctuation">,</span><br /> GROUP_CONCAT<span class="token punctuation">(</span><span class="token keyword">DISTINCT</span> test_score<br /> <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> test_score <span class="token keyword">DESC</span> SEPARATOR <span class="token string">' '</span><span class="token punctuation">)</span><br /><span class="token keyword">FROM</span> student<br /><span class="token keyword">GROUP</span> <span class="token keyword">BY</span> student_name<span class="token punctuation">;</span></code></pre>
<p>Here the query will get the distinct test_score highest first grouped by student and separated by a space character.</p>
<p>Now that we have a clear understanding of what string_agg is and how it compares to group_concat, let's move on to some practical examples using real data of billionaires of the world.</p>
<h2 id="example-of-billionaires-data" tabindex="-1">Example of billionaires data <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#example-of-billionaires-data">#</a></h2>
<p>Yes, you heard it right, the top 100 billionaires of the world. Thankfully, Kaggle has a <a href="https://www.kaggle.com/datasets/nelgiriyewithana/billionaires-statistics-dataset">billionaires dataset</a> of 2023 that lists 2540 billionaires in the world with many fields. I downloaded the CSV and removed most of the fields not relevant to this example. I also took only the top 100 billionaires from that list to create a Postgres table as follows:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token string">"billionaire"</span> <span class="token punctuation">(</span><br /> <span class="token string">"id"</span> <span class="token keyword">serial</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span><br /> <span class="token string">"rank"</span> <span class="token keyword">integer</span><span class="token punctuation">,</span><br /> <span class="token string">"worth"</span> <span class="token keyword">integer</span><span class="token punctuation">,</span><br /> <span class="token string">"name"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"gender"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"category"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"country"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"city"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"source"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"industries"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"citizenship_country"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"organization"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"title"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"birth_year"</span> <span class="token keyword">integer</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>I have deliberately kept the structure very simple and have not added any index or unique indexes to the table as it will have only 100 rows. The goal of this tutorial is to understand the Postgres string_agg function, not something else. The data of the 10 (or 100) billionaires can be inserted with the following insert statement:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> <span class="token string">"billionaire"</span> <span class="token punctuation">(</span><br /> rank<span class="token punctuation">,</span> worth<span class="token punctuation">,</span> name<span class="token punctuation">,</span> gender<span class="token punctuation">,</span> category<span class="token punctuation">,</span> country<span class="token punctuation">,</span> city<span class="token punctuation">,</span> <br /> source<span class="token punctuation">,</span> industries<span class="token punctuation">,</span> citizenship_country<span class="token punctuation">,</span> organization<span class="token punctuation">,</span> title<span class="token punctuation">,</span> birth_year<br /><span class="token punctuation">)</span> <span class="token keyword">VALUES</span><br /><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">211000</span><span class="token punctuation">,</span><span class="token string">'Bernard Arnault & family'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Fashion & Retail'</span><span class="token punctuation">,</span><span class="token string">'France'</span><span class="token punctuation">,</span><span class="token string">'Paris'</span><span class="token punctuation">,</span><span class="token string">'LVMH'</span><span class="token punctuation">,</span><span class="token string">'Fashion & Retail'</span><span class="token punctuation">,</span><span class="token string">'France'</span><span class="token punctuation">,</span><span class="token string">'LVMH Moët Hennessy Louis Vuitton'</span><span class="token punctuation">,</span><span class="token string">'Chairman and CEO'</span><span class="token punctuation">,</span><span class="token number">1949</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">180000</span><span class="token punctuation">,</span><span class="token string">'Elon Musk'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Automotive'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Austin'</span><span class="token punctuation">,</span><span class="token string">'Tesla, SpaceX'</span><span class="token punctuation">,</span><span class="token string">'Automotive'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Tesla'</span><span class="token punctuation">,</span><span class="token string">'CEO'</span><span class="token punctuation">,</span><span class="token number">1971</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">114000</span><span class="token punctuation">,</span><span class="token string">'Jeff Bezos'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Medina'</span><span class="token punctuation">,</span><span class="token string">'Amazon'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Amazon'</span><span class="token punctuation">,</span><span class="token string">'Chairman and Founder'</span><span class="token punctuation">,</span><span class="token number">1964</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">107000</span><span class="token punctuation">,</span><span class="token string">'Larry Ellison'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Lanai'</span><span class="token punctuation">,</span><span class="token string">'Oracle'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Oracle'</span><span class="token punctuation">,</span><span class="token string">'CTO and Founder'</span><span class="token punctuation">,</span><span class="token number">1944</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">106000</span><span class="token punctuation">,</span><span class="token string">'Warren Buffett'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Finance & Investments'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Omaha'</span><span class="token punctuation">,</span><span class="token string">'Berkshire Hathaway'</span><span class="token punctuation">,</span><span class="token string">'Finance & Investments'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Berkshire Hathaway Inc. (Cl A)'</span><span class="token punctuation">,</span><span class="token string">'CEO'</span><span class="token punctuation">,</span><span class="token number">1930</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">104000</span><span class="token punctuation">,</span><span class="token string">'Bill Gates'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Medina'</span><span class="token punctuation">,</span><span class="token string">'Microsoft'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Bill & Melinda Gates Foundation'</span><span class="token punctuation">,</span><span class="token string">'Cochair'</span><span class="token punctuation">,</span><span class="token number">1955</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span><span class="token number">94500</span><span class="token punctuation">,</span><span class="token string">'Michael Bloomberg'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Media & Entertainment'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'New York'</span><span class="token punctuation">,</span><span class="token string">'Bloomberg LP'</span><span class="token punctuation">,</span><span class="token string">'Media & Entertainment'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Bloomberg'</span><span class="token punctuation">,</span><span class="token string">'CEO'</span><span class="token punctuation">,</span><span class="token number">1942</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">93000</span><span class="token punctuation">,</span><span class="token string">'Carlos Slim Helu & family'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Telecom'</span><span class="token punctuation">,</span><span class="token string">'Mexico'</span><span class="token punctuation">,</span><span class="token string">'Mexico City'</span><span class="token punctuation">,</span><span class="token string">'Telecom'</span><span class="token punctuation">,</span><span class="token string">'Telecom'</span><span class="token punctuation">,</span><span class="token string">'Mexico'</span><span class="token punctuation">,</span><span class="token string">'América Móvil'</span><span class="token punctuation">,</span><span class="token string">'Honorary Chairman'</span><span class="token punctuation">,</span><span class="token number">1940</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span><span class="token number">83400</span><span class="token punctuation">,</span><span class="token string">'Mukesh Ambani'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Diversified'</span><span class="token punctuation">,</span><span class="token string">'India'</span><span class="token punctuation">,</span><span class="token string">'Mumbai'</span><span class="token punctuation">,</span><span class="token string">'Diversified'</span><span class="token punctuation">,</span><span class="token string">'Diversified'</span><span class="token punctuation">,</span><span class="token string">'India'</span><span class="token punctuation">,</span><span class="token string">'Reliance Industries'</span><span class="token punctuation">,</span><span class="token string">'Founder and Chairman'</span><span class="token punctuation">,</span><span class="token number">1957</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span><span class="token number">80700</span><span class="token punctuation">,</span><span class="token string">'Steve Ballmer'</span><span class="token punctuation">,</span><span class="token string">'M'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Hunts Point'</span><span class="token punctuation">,</span><span class="token string">'Microsoft'</span><span class="token punctuation">,</span><span class="token string">'Technology'</span><span class="token punctuation">,</span><span class="token string">'United States'</span><span class="token punctuation">,</span><span class="token string">'Los Angeles Clippers'</span><span class="token punctuation">,</span><span class="token string">'Owner'</span><span class="token punctuation">,</span><span class="token number">1956</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The above is not the full list of top 100 billionares in 2023, it is just the 10. You can get the full list of top 100 in this <a href="https://gist.github.com/geshan/b2495283109e19a8e19af837a5c8eb50#file-02billionarire-data-sql">gist</a>.</p>
<p>You can run <a href="https://geshan.com.np/blog/2021/12/docker-postgres/">Postgres with Docker</a> and Docker Compose locally. Still, The easiest way for you to test this without needing to install Postgres locally will be to use ElephantSQL. Their <a href="https://www.elephantsql.com/plans.html">free plan</a> will give you a database with a max of 20MB of data and 5 concurrent connections which is more than enough to try out this example. You can follow their official <a href="https://www.elephantsql.com/docs/index.html">getting started documentation</a> to set up a database and insert the date using the above SQL statements.</p>
<p>Once you have the database set up with the 100 rows added. You can ask various questions as you will do in the next section.</p>
<h2 id="list-the-billionaires-by-country-and-birth-year-with-count-per-country" tabindex="-1">List the billionaires by country and birth year with count per country <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#list-the-billionaires-by-country-and-birth-year-with-count-per-country">#</a></h2>
<p>You can get answers to questions like listing all the billionaires by country and year of birth youngest first with the count by country. It can be done easily by using the <code>string_agg</code> function in Postgres as below:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span><br /> b<span class="token punctuation">.</span>country<span class="token punctuation">,</span><br /> STRING_AGG <span class="token punctuation">(</span><br /> b<span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token string">' - '</span> <span class="token operator">||</span> b<span class="token punctuation">.</span>birth_year<span class="token punctuation">,</span> <span class="token string">', '</span><br /> <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> b<span class="token punctuation">.</span>birth_year <span class="token keyword">DESC</span><br /> <span class="token punctuation">)</span> <span class="token keyword">AS</span> billionaire_birth_year<span class="token punctuation">,</span><br /> <span class="token function">COUNT</span><span class="token punctuation">(</span>b<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token keyword">as</span> no_of_billionaires<br /><span class="token keyword">FROM</span><br /> billionaire b<br /><span class="token keyword">GROUP</span> <span class="token keyword">BY</span><br /> b<span class="token punctuation">.</span>country<br /><span class="token keyword">ORDER</span> <span class="token keyword">BY</span> no_of_billionaires <span class="token keyword">DESC</span><span class="token punctuation">;</span></code></pre>
<p>The output will look like the below:</p>
<img class="center" src="https://geshan.com.np/images/postgres-string_agg/02postgres-string_agg-example.jpg" title="Top 100 Billionares with Birth year by country and count per country" alt="Top 100 Billionares with Birth year by country and count per country" />
<p>The output has been truncated with the top 10 rows but it will list all the 20 rows/countries if you run it on ElephantSQL Browser or any other CLI tool like <a href="https://www.postgresql.org/docs/current/app-psql.html">psql</a> or a GUI like <a href="https://www.jetbrains.com/datagrip/">DataGrip</a>. You can already see the power of string_agg function in PostgreSQL. Let’s ask one more question in the next section and that will be all the examples.</p>
<h2 id="list-the-billionaires-by-category-and-count-per-category" tabindex="-1">List the billionaires by category and count per category <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#list-the-billionaires-by-category-and-count-per-category">#</a></h2>
<p>The query this time is which category of work has the most billionaires and list the names alphabetically and number of billionaires by category. It can be achieved by:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span><br /> b<span class="token punctuation">.</span>category<span class="token punctuation">,</span><br /> STRING_AGG <span class="token punctuation">(</span><br /> b<span class="token punctuation">.</span>name<span class="token punctuation">,</span> <span class="token string">', '</span><br /> <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> b<span class="token punctuation">.</span>name <span class="token keyword">ASC</span><br /> <span class="token punctuation">)</span> <span class="token keyword">AS</span> billionaire_names<span class="token punctuation">,</span><br /> <span class="token function">COUNT</span><span class="token punctuation">(</span>b<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token keyword">as</span> no_of_billionaires<br /><span class="token keyword">FROM</span><br /> billionaire b<br /><span class="token keyword">GROUP</span> <span class="token keyword">BY</span><br /> b<span class="token punctuation">.</span>category<br /><span class="token keyword">ORDER</span> <span class="token keyword">BY</span> no_of_billionaires <span class="token keyword">DESC</span><span class="token punctuation">;</span></code></pre>
<p>The output will look like the below:</p>
<img class="center" src="https://geshan.com.np/images/postgres-string_agg/03postgres-string_agg-billionaires.jpg" title="Top 100 Billionaires by category and count per category" alt="Top 100 Billionaires by category and count per category" />
<p>Surely in 2023, there will be more billionaires making their money from the technology category than any other. For instance, in the top 100 billionaires of the world Real Estate has 2 whereas tech has 16, so work in tech :). You can play around with the data and ask more questions to get more insights with SQL and string_agg.</p>
<h2 id="using-string_agg-with-within-group" tabindex="-1">Using string_agg with WITHIN GROUP <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#using-string_agg-with-within-group">#</a></h2>
<p>In addition to the basic usage of string_agg, PostgreSQL provides an extension to this function called WITHIN GROUP, allowing you to specify the order in which values are concatenated within each group, which is particularly valuable when the sequence of items in the concatenated string is significant.</p>
<p>The syntax for using WITHIN GROUP is as follows:</p>
<pre class="language-sql"><code class="language-sql">string_agg<span class="token punctuation">(</span>expression<span class="token punctuation">,</span> <span class="token keyword">delimiter</span><span class="token punctuation">)</span> <span class="token keyword">WITHIN</span> <span class="token keyword">GROUP</span> <span class="token punctuation">(</span><span class="token keyword">ORDER</span> <span class="token keyword">BY</span> ordering_expression<span class="token punctuation">)</span></code></pre>
<p>The WITHIN GROUP extension in PostgreSQL's string_agg function enables ordered concatenation, providing control over the sequence of values within each group. This functionality proves especially useful for tasks like listing products sorted by prices.</p>
<p>Let's update the aforementioned query to obtain answers to questions such as listing all the billionaires by country and year of birth, with the youngest first, along with the count by country:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span><br /> b<span class="token punctuation">.</span>country<span class="token punctuation">,</span><br /> STRING_AGG <span class="token punctuation">(</span><br /> b<span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token string">' - '</span> <span class="token operator">||</span> b<span class="token punctuation">.</span>birth_year<span class="token punctuation">,</span> <span class="token string">', '</span><br /> <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> b<span class="token punctuation">.</span>birth_year <span class="token keyword">DESC</span><br /> <span class="token keyword">WITHIN</span> <span class="token keyword">GROUP</span> <span class="token punctuation">(</span><span class="token keyword">ORDER</span> <span class="token keyword">BY</span> b<span class="token punctuation">.</span>birth_year <span class="token keyword">DESC</span><span class="token punctuation">)</span><br /> <span class="token punctuation">)</span> <span class="token keyword">AS</span> billionaire_birth_year<span class="token punctuation">,</span><br /> <span class="token function">COUNT</span><span class="token punctuation">(</span>b<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token keyword">as</span> no_of_billionaires<br /><span class="token keyword">FROM</span><br /> billionaire b<br /><span class="token keyword">GROUP</span> <span class="token keyword">BY</span><br /> b<span class="token punctuation">.</span>country<br /><span class="token keyword">ORDER</span> <span class="token keyword">BY</span> no_of_billionaires <span class="token keyword">DESC</span><span class="token punctuation">;</span></code></pre>
<p>In this query, the string_agg function will concatenate billionaire names along with their birth years (ordered by birth year in descending order) within each country group and count the number of billionaires in each country, ultimately sorting the results by the number of billionaires in descending order.</p>
<p>Did you notice any difference? In this query, we added 'WITHIN GROUP'. The key distinction is that the previous query applies the ordering to the entire result set, whereas in this one, we ensure that the concatenation is ordered within each country group as well.</p>
<p>Why does this matter? Consider a scenario where the order of items in the concatenated string is crucial, such as when creating a comma-separated list of items in a specific sequence. The WITHIN GROUP extension empowers you to control this order, providing a powerful tool for precise string aggregation.</p>
<p>It's important to note that if the order of items is not significant for your use case, you can continue to use string_agg without WITHIN GROUP as demonstrated earlier.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/10/postgres-string_agg/#conclusion">#</a></h2>
<p>PostgreSQL's string_agg function is a powerful tool for string aggregation in SQL queries. It allows you to concatenate values from multiple rows into a single string, making it ideal for tasks such as generating comma-separated lists or creating custom reports.</p>
<p>In this blog post, you found out what string_agg is and how it relates to MySQL's group_concat. You also learned its practical use with real data, including listing billionaires by country and category.</p>
<p>The next time you find yourself working on a PostgreSQL project that involves string aggregation, remember the string_agg function and how it can simplify your queries and data processing. Happy querying!</p>
There are like nine actual full-stack engineers in the world, and you are NOT one of them2023-10-21T11:45:57Zhttps://geshan.com.np/blog/2023/10/full-stack-engineer/<p>The term “full-stack engineer” is often thrown around in the software industry, particularly in web development. Let me break the news to you, a real full-stack engineer is a mythical unicorn. In this post, you will learn about how and why there are ~nine actual full-stack engineers in this world, and you are not one of them. Still, you can be very successful in your software engineering career, carry on reading to know how.</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/full-stack-engineer/01full-stack-engineer.jpg" title="There are like nine actual full-stack engineers in the world, and you are not one of the unicorns" alt="There are like nine actual full-stack engineers in the world, and you are not one of the unicorns" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#what-is-a-full-stack-engineer%3F">What is a full-stack engineer?</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#how-are-there-like-nine-full-stack-engineers%2C-really">How are there like nine full-stack engineers, really</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#there-are-surely-no-junior-full-stack-engineers">There are surely no junior full-stack engineers</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#backend-is-diversified-in-languages">Backend is diversified in languages</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#frontend-varies-on-the-framework-aspect">Frontend varies on the framework aspect</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#choose-your-specialization-and-make-it-your-forte">Choose your specialization and make it your forte</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#become-a-t-shaped-product-minded-engineer">Become a T-Shaped product-minded engineer</a></li>
<li><a href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#conclusion">Conclusion</a></li>
</ul>
<h2 id="what-is-a-full-stack-engineer%3F" tabindex="-1">What is a full-stack engineer? <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#what-is-a-full-stack-engineer%3F">#</a></h2>
<p>A full-stack engineer is a software engineer who can work on both the frontend and backend of a web application. They are proficient in both frontend and backend technologies and can work on all aspects of a web application, from the user interface to the database. They are also known as full-stack developers or full-stack web developers. But really, they are mythical unicorns, let's understand how in the next section.</p>
<h2 id="how-are-there-like-nine-full-stack-engineers%2C-really" tabindex="-1">How are there like nine full-stack engineers, really <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#how-are-there-like-nine-full-stack-engineers%2C-really">#</a></h2>
<p>As per this post about <a href="https://cloud.google.com/blog/products/application-development/richard-seroter-on-shifting-down-vs-shifting-left">Shift left vs shift down</a> by <a href="https://seroter.com/about/">Richard Seroter</a>. He is the Director of Developer Relations and Outbound Product Management at Google Cloud and has multiple courses on Plural Sight, some of them being about Devops, Java, and Serverless. So he surely knows what he is talking about. Let me pull a quote from that post:</p>
<blockquote>
<p>There are like nine actual “full stack engineers” on planet Earth. Virtually nobody writes a frontend in React, sets up Kubernetes, configures a RabbitMQ instance, provisions space on the SAN, and lights up the top-of-rack switch.</p>
</blockquote>
<p>When someone advertises for a real “full-stack” engineer they really mean is we have a budget for a person but that person should work as a team of 2-4 people.</p>
<blockquote>
<p>So a full stack engineer supposedly can do at least both backend and frontend work equally well.</p>
</blockquote>
<p>It is surely more than one person because a full-stack engineer should know the “full-stack” of the application which even oversimplified looks like the following visually:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/backend-vs-frontend/02backend-frontend.jpg" title="Backend, Frontend, Full-stack, and Super Stack oversimplified" alt="Backend, Frontend, Full-stack, and Super Stack oversimplified" />
<p>Now with that image in your mind, let’s go deeper into why a real full-stack engineer only exists in fictional stories or superhero movies. So in the next part, you will know that, alas, a junior full-stack engineer can never exist.</p>
<h2 id="there-are-surely-no-junior-full-stack-engineers" tabindex="-1">There are surely no junior full-stack engineers <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#there-are-surely-no-junior-full-stack-engineers">#</a></h2>
<p>First things first, let's dispel the myth of junior full-stack engineers. The concept of a junior full-stack engineer is similar to a novice pilot flying a jumbo jet, which is impossible. Full-stack engineering requires a deep understanding of both the front-end and back-end, which typically comes with years and years of experience.</p>
<p>Junior engineers, who are in the early stages of their careers, are still building their foundational skills and exploring different aspects of development.</p>
<blockquote>
<p>It's crucial to understand that a strong foundation in a specific area is the first step before branching out into “so-called” full-stack development.</p>
</blockquote>
<p>In the next section, you will learn more about the backend software work, one of these specific areas.</p>
<h2 id="backend-is-diversified-in-languages" tabindex="-1">Backend is diversified in languages <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#backend-is-diversified-in-languages">#</a></h2>
<p>The backend side of web development is a multifaceted landscape. I have discussed <a href="https://geshan.com.np/blog/2020/02/difference-between-backend-frontend/#backend-development">backend development</a> work in the past too. Backend development work will involve working with at least one backend language like PHP, NodeJs, Ruby, Python, Java, etc which can communicate with a database/datastore. As you can see, there are diverse programming languages and technologies involved.</p>
<p>Learning one takes time and to master one you will need to invest years of your life. To master all of these languages and their respective ecosystems is a close to impossible task. Not only does each language require time to learn, but keeping up with updates and best practices can be a lot more than a full-time job.</p>
<p>I did not even touch on the varieties of databases from relational (read SQL) to non-relational databases you might want to learn in the backend realm. Each language and database serves different purposes, and they come with their own sets of strengths and weaknesses.</p>
<blockquote>
<p>Being a proficient backend engineer with a combination of a single programming language and one database will take you years. If you are thinking of learning more than one programming language and 2-3 databases and using them in production environments, you are looking at a decade or more of time investment.</p>
</blockquote>
<p>Now you see how rigorous, difficult, and time-consuming being a great backend engineer is. In the next section, you will learn about how the frontend side is fragmented.</p>
<h2 id="frontend-varies-on-the-framework-aspect" tabindex="-1">Frontend varies on the framework aspect <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#frontend-varies-on-the-framework-aspect">#</a></h2>
<p>Frontend development is equally varied, marked by a multitude of frameworks and libraries. Frontend development work encompasses the ability to change how things look and how users interact with the website or web/mobile application. It includes wrangling with HTML, CSS, and our favorite JavaScript. Frontend JavaScirpt is if I can use the word “fragmented” in frameworks.</p>
<p>Angular, React, Vue.js, Svelte, and many others are part of the landscape. React is the most <a href="https://docs.google.com/spreadsheets/d/1kODyUrTPWvz5n0fpUovRdxfXsSikVHz6T3h9Kspuk8g/edit#gid=81955775">popular one</a> (check the other sheets too). Each of these frameworks has its unique syntax, structure, and set of conventions. Staying proficient in all of them is near impossible, especially given the rapid pace of change in the world of web development. And then a new JavaScirpt framework pops up every other week, and then you hear terms like <a href="https://www.freecodecamp.org/news/the-cure-to-js-fatigue/">JavaScript Fatigue</a>. And then you end up asking <a href="https://matt-rickard.com/why-is-the-frontend-stack-so-complicated">why is frontend stack so complicated</a> and <a href="https://alexkondov.com/the-hard-things-about-front-end-development/">hard</a>. On top of that <a href="https://geshan.com.np/blog/2022/09/software-engineering-realities/#languages-and-frameworks">language and frameworks</a> have popularity cycles, so because React is the most popular now does not mean in 5 years it will still be the most popular.</p>
<p>There has been a slow use of <a href="https://webassembly.org/">Web Assembly</a> - Wasm. WebAssembly is an exciting development in the world of web technology. It's a binary instruction format that enables high-performance execution of code on web browsers. With WebAssembly, you can write code in languages like C, C++, and Rust and run it in web applications. But it is far from mainstream as of 2023. Thereby:</p>
<blockquote>
<p>Being a great frontend engineer (from a technical point of view), requires years of learning JavaScript and understanding its ever-changing eco-system of build tools, bundlers etc. Then on top of it knowing at least one framework very well. All this equates to, again a decade or more of time investment.</p>
</blockquote>
<p>So now that you are clear a full-stack engineer is an illusion created by companies who want to replace a team of 2-3 people with one person who is supposed to do all the work. Unless it is a company that has a revenue of less than 6 figures, it would be an impossible task to even attempt. So in the next section, you will learn about the practical path of being a software engineer with focus.</p>
<h2 id="choose-your-specialization-and-make-it-your-forte" tabindex="-1">Choose your specialization and make it your forte <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#choose-your-specialization-and-make-it-your-forte">#</a></h2>
<p>Selecting a specialization and making it your forte is the strategic move in your tech career. You have to choose one path backend, frontend, or even data, cloud, ML – but only one thing.</p>
<blockquote>
<p>You can surely be a great backend engineer who can do some frontend and vice versa.</p>
</blockquote>
<p>Regardless of your chosen specialization be it backend, frontend or something else, a strong foundation in the basics is crucial. This is discussed in the <a href="https://geshan.com.np/blog/2017/02/things-i-wished-i-knew-as-a-junior-developer-slides/">junior software engineer</a> post too. With a deep understanding of fundamental programming concepts, data structures, and algorithms, things like HTTP serve as your bedrock. These principles are the keys to solving complex problems and thinking critically as an engineer. Being proficient in the fundamentals allows you to adapt and excel in various contexts and technologies, making you a more valuable asset to your team and organization.</p>
<p>Even with 15 years of practical work experience in 3 continents and million-dollar companies, I would refrain from calling myself a “full-stack” engineer.</p>
<blockquote>
<p>This does not mean that I will never touch frontend or backend or vice-versa. I will consider myself a solution provider and as per need, I will deliver end-to-end solutions.</p>
</blockquote>
<p>Still, as my frontend skills are not as good as my backend skills, I will let the product manager know that if I do the frontend task it will take longer for me to do it than a frontend engineer whose forte is frontend work. That is where you need to understand the T-shaped engineer, discussed next.</p>
<h2 id="become-a-t-shaped-product-minded-engineer" tabindex="-1">Become a T-Shaped product-minded engineer <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#become-a-t-shaped-product-minded-engineer">#</a></h2>
<p>A <a href="https://alexkondov.com/the-t-shaped-engineer/">T-shaped engineer</a> is someone who has broad knowledge across multiple disciplines but focuses on one the most. The concept of a T-shaped engineer is a pragmatic approach to handling the complexity of modern software development.</p>
<blockquote>
<p>Rather than attempting to master every facet of the tech stack, a T-shaped engineer chooses to go deep in one specific area while maintaining a broader set of skills across the stack.</p>
</blockquote>
<p>The vertical line of the 'T' represents your depth of knowledge in your chosen specialization, while the horizontal line signifies your understanding of other areas.</p>
<p>The advantage of being a T-shaped engineer is that you can become an expert in one domain while still being able to communicate and collaborate effectively across various aspects of a project. This allows you to specialize, become proficient, and make a significant impact in your area of choice while remaining versatile enough to adapt to different projects and teams. You can see an illustration of a T-shaped engineer from a <a href="https://twitter.com/pvukovic/status/1503664394298929157">tweet</a> by Peter Vukovic below:</p>
<img class="center" src="https://geshan.com.np/images/full-stack-engineer/02t-shaped-eng.jpg" title="An example T-shaped engineer with a focus on backend development" alt="An example T-shaped engineer with a focus on backend development" />
<p>A T-Shaped <a href="https://blog.pragmaticengineer.com/the-product-minded-engineer/">product-minded engineer</a> would be a great software engineer. Product-minded engineers are developers with a lots of interest in the product itself. They want to understand why decisions are made, and how people use the product, and love to be involved in making product decisions. Product-minded engineers are curious, proactive, and have strong communication skills. They are also able to see the big picture and understand the business goals.</p>
<blockquote>
<p>To sum it up, specialize in one domain (be it backend or frontend or something else) but have a border knowledge of the technology landscape then have the business acumen and know about the who, why, and how of the product you are building.</p>
</blockquote>
<p>Don’t try to become something impossible to exist and keep up with. Have realistic expectations and become a valuable team member and someone who adds a lot of value to the organization you work for.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/10/full-stack-engineer/#conclusion">#</a></h2>
<p>In conclusion, the myth of the full-stack engineer often leads to unrealistic expectations and unnecessary stress for aspiring tech professionals. A junior full-stack engineer is non-existent and it takes years and years (read decades) of experience to become a great Backend engineer. It takes a similar amount of time to become a proficient Frontend engineer and ongoing time investment to keep up to date with the ever-changing landscape of software engineering.</p>
<blockquote>
<p>Thereby it is humanly not possible to be a real full-stack engineer. You are not one of the nine actual full-stack engineers that probably exist in this world.</p>
</blockquote>
<p>On the contrary, it is possible to specialize in one area be it backend or frontend or any other, and become a super useful and valuable T-shaped product-minded engineer who adds immense value to the organization.</p>
A beginner's guide to retrying failed requests with Axios Retry2023-09-26T11:41:57Zhttps://geshan.com.np/blog/2023/09/axios-retry/<p>In the ever-evolving world of web development, handling HTTP requests is a fundamental task. Whether you're building a frontend application or a backend service, you'll likely find yourself dealing with APIs and remote servers. <a href="https://axios-http.com/docs/intro">Axios</a>, a popular JavaScript library, simplifies the process of making HTTP requests. However, what happens when those requests fail? In this beginner’s guide, you will explore how to tackle this issue by using <a href="https://www.npmjs.com/package/axios-retry">Axios Retry</a>, an essential plugin that can save you time and frustration. Let's get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/axios-retry/01axios-retry.jpg" title="A beginner's guide to retrying failed requests with Axios Retry" alt="A beginner's guide to retrying failed requests with Axios Retry" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#benefits-of-retrying-a-failed-request">Benefits of Retrying a Failed Request</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#what-is-axios">What is Axios?</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#why-use-axios-retry">Why Use Axios Retry</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#axios-retry-config">Axios retry config</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#axios-retry-example">Axios retry example</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#install-axios-retry">Install Axios retry</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#use-axios-retry-to-retry-failed-requests">Use axios retry to retry failed requests</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#npmtrends-comparison">NpmTrends comparison</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/axios-retry/#conclusion">Conclusion</a></li>
</ul>
<h2 id="benefits-of-retrying-a-failed-request" tabindex="-1">Benefits of Retrying a Failed Request <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#benefits-of-retrying-a-failed-request">#</a></h2>
<p>Before delving into Axios and Axios Retry, let's understand the importance of retrying failed requests. In a real-world web application, network issues, server errors, or temporary glitches can cause HTTP requests to fail. Retrying failed requests can provide several benefits as listed below:</p>
<ul>
<li>
<p>Improved Reliability: By automatically retrying failed requests, you increase the likelihood of successful data retrieval, improving the overall reliability of your application.</p>
</li>
<li>
<p>Enhanced User Experience: Retrying requests silently in the background can ensure a seamless user experience without error messages or interruptions.</p>
</li>
<li>
<p>Reduced Manual Intervention: Without automated retry mechanisms, developers may need to intervene and manually retry requests, which is neither efficient nor scalable.</p>
</li>
</ul>
<p>With the above in mind, in the next part, you will learn about Axios.</p>
<h2 id="what-is-axios%3F" tabindex="-1">What is Axios? <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#what-is-axios%3F">#</a></h2>
<p><a href="https://axios-http.com/docs/intro">Axios</a> is a promise-based HTTP client for JavaScript, which means it allows you to send asynchronous HTTP requests to REST endpoints or other services. It is widely used in both frontend and backend development due to its simplicity and versatility. With Axios, you can perform various HTTP operations such as GET, POST, PUT, DELETE, and more with ease. Even though there are other alternatives to Axios, it is one of the <a href="https://npmtrends.com/axios-vs-got-vs-node-fetch-vs-request-vs-superagent">most popular</a> HTTP client libraries for both the backend (Node.js) and the front end.</p>
<p>In the next section, you will learn how to retry failed idempotent requests in Axios using the Axios retry plugin and the why behind it.</p>
<h2 id="why-use-axios-retry" tabindex="-1">Why Use Axios Retry <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#why-use-axios-retry">#</a></h2>
<p>Axios Retry is an Axios plugin that simplifies the process of retrying failed requests. It offers a straightforward way to add resilience to your HTTP requests by allowing you to specify the number of retry attempts and a custom retry delay between each attempt. Here are some compelling reasons to use Axios Retry:</p>
<ul>
<li>
<p>Saves Development Time: Writing custom retry logic for every request can be time-consuming. Axios Retry streamlines this process, saving you development time.</p>
</li>
<li>
<p>Customizable Retry Strategies: You can define custom retry strategies based on the specific needs of your application, such as increasing the delay between retries or limiting the number of attempts.</p>
</li>
<li>
<p>Enhances Code Readability: By encapsulating retry logic within Axios interceptors, your code remains clean and maintainable, improving readability.</p>
</li>
</ul>
<p>Axios retry plugin has a flexible config you can use, which is described in the next section.</p>
<h3 id="axios-retry-config" tabindex="-1">Axios retry config <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#axios-retry-config">#</a></h3>
<p>You can find some code examples in the Axios retry <a href="https://github.com/softonic/axios-retry">GitHub</a> repository. It also lists down the configuration options with their type, default values, and description of what it does in a neatly organized <a href="https://github.com/softonic/axios-retry#options">table</a>.</p>
<p>The main configs from that table are:</p>
<ul>
<li>Retries - number of retries to do when the request fails.</li>
<li>Retry condition - the condition should pass for the next retry to take place. By default, it retries on 5xx errors on idempotent requests.</li>
<li>Retry delay - the delay in milliseconds between retrieved requests. <a href="https://developers.google.com/analytics/devguides/reporting/core/v3/errors#backoff">Exponential backoff</a> is one of the best strategies for it.</li>
</ul>
<p>Below is an example that uses all the above configs.</p>
<h2 id="axios-retry-example" tabindex="-1">Axios retry example <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#axios-retry-example">#</a></h2>
<p>Let's dive into a practical example to demonstrate how Axios Retry works. Consider a scenario where you're making an API request, and the server returns a 500 Internal Server Error. Without Axios Retry or any other retry mechanism, the request will fail and stop on the first failure like a 500 response from the server.</p>
<p>Now, let's see how to achieve retrying with some rules using Axios Retry, next.</p>
<h3 id="install-axios-retry" tabindex="-1">Install Axios retry <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#install-axios-retry">#</a></h3>
<p>For the scope of this example, you will use Axios and Axios retry. To install both of them with NPM you can run:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> axios axios-retry</code></pre>
<p>At the time of writing, the latest version of Axios was 1.5.0, and Axios retry was 3.8.0. If you want to only install Axios retry you can run <code>npm install axios-retry</code>.</p>
<p>For this example, you will send an HTTP GET request to a dummy server by Postman called Postman Echo and retry on the failure. The code for retrying the failed example can be found in the following section.</p>
<h3 id="use-axios-retry-to-retry-failed-requests" tabindex="-1">Use axios retry to retry failed requests <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#use-axios-retry-to-retry-failed-requests">#</a></h3>
<p>For the request retry example, while calling the Postman Echo test server, you will follow some rules. The rules are, that you will retry 3 times and there will be a delay of more than 1 * no. of retries second + random number of milliseconds between each retry – this is the <a href="https://cloud.google.com/iot/docs/how-tos/exponential-backoff#example_algorithm">exponential backoff</a> algorithm. The retry will be done only in the case of <code>500</code> and <code>501</code> response codes.</p>
<p>Just to complete the circuit, you will change the request URL after 2 retries to a URL that sends back a 200 response so that the third retry is not required. You will also log the number of retries and response status if the request is successful. Below is the code that follows all these rules in a file named <code>index.js</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><br /><span class="token keyword">import</span> axiosRetry <span class="token keyword">from</span> <span class="token string">'axios-retry'</span><span class="token punctuation">;</span><br /> <br /><span class="token function">axiosRetry</span><span class="token punctuation">(</span>axios<span class="token punctuation">,</span> <span class="token punctuation">{</span> <br /> <span class="token literal-property property">retries</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">retryDelay</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>arg</span><span class="token punctuation">)</span> <span class="token operator">=></span> axiosRetry<span class="token punctuation">.</span><span class="token function">exponentialDelay</span><span class="token punctuation">(</span><span class="token operator">...</span>arg<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">retryCondition</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">switch</span> <span class="token punctuation">(</span>error<span class="token punctuation">.</span>response<span class="token punctuation">.</span>status<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">//retry only if status is 500 or 501</span><br /> <span class="token keyword">case</span> <span class="token number">500</span><span class="token operator">:</span><br /> <span class="token keyword">case</span> <span class="token number">501</span><span class="token operator">:</span><br /> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token keyword">default</span><span class="token operator">:</span><br /> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">onRetry</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">retryCount<span class="token punctuation">,</span> error<span class="token punctuation">,</span> requestConfig</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">retry count: </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> retryCount<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span><span class="token punctuation">(</span>retryCount <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> requestConfig<span class="token punctuation">.</span>url <span class="token operator">=</span> <span class="token string">'https://postman-echo.com/status/200'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <br /><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'https://postman-echo.com/status/500'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">inside async:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> res<span class="token punctuation">.</span>status<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error occurred: </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> err<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You first import <code>axios</code> and <code>axois retry</code> in the above script. Then set the config for Axios retry to follow all the above defined rules of 3 retries and exponential backoff.</p>
<p>Then in the async function, you call the Postman Echo endpoint that always sends back a 500. If you are using Node 18+ and <code>module</code> in package.json you can try <a href="https://github.com/geshan/axios-retry/blob/master/index.js#L34-L36">top-level await</a> too. In case of an error, it is logged. If the response comes back successfully the status code is logged.</p>
<p>Another interesting aspect to note here is, that each retry attempt number is logged in the <code>onRetry</code> function. After retry no. 2, you change the request URL to become successful. To make the requests more resilient you can also add a <a href="https://geshan.com.np/blog/2022/11/axios-timeout/">timeout to Axios</a> request. The script runs like below when you run it with <code>time node index.js</code> (you can also use <code>node index.js</code>, time is used here to see how long the whole script takes:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/axios-retry/02axios-retry-script-run.jpg" title="Axios retry script with 3 retries and exponetial backoff output" alt="Axios retry script with 3 retries and exponetial backoff output" />
<p>Because of the exponential backoff, the script takes 11.5 seconds to run after 2 retires. You can find this code in an open source <a href="https://github.com/geshan/axios-retry">GitHub repository</a> for your reference. In the next section, you will learn about how do other alternatives to Axios retry compare to it.</p>
<h2 id="npmtrends-comparison" tabindex="-1">NpmTrends comparison <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#npmtrends-comparison">#</a></h2>
<p>There are not many alternatives to Axois Retry. One of them is Retry Axois but it is not as popular as the Axios Retry. Of course, you can whip up your own solution using <a href="https://geshan.com.np/blog/2022/12/axios-interceptors/">Axois interceptors</a> but that won’t be an optimal solution. Below is a quick comparison of the alternatives retry Axios and Axios retry interceptor from <a href="https://npmtrends.com/axios-retry-vs-axios-retry-interceptor-vs-retry-axios">NPM Trends</a> :</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/axios-retry/03axios-retry-alt-comparision.jpg" title="Axios retry popularity comparision to its alternatives" alt="Axios retry popularity comparision to its alternatives" />
<p>As you can see, Axios Retry currently has more than 2.5 million downloads per week whereas Retry Axios has around 600K downloads per week. Similarly, <code>axios-retry-interceptor</code> has only around 50 downloads per week. So, it is safe to say that Axios Retry is the most popular retry plugin/library for retrying requests in Axios.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/09/axios-retry/#conclusion">#</a></h2>
<p>In this beginner's guide, you have explored the world of Axios Retry and its significance in handling failed HTTP requests. You have seen how Axios Retry simplifies the process of adding retry mechanisms to your Axios requests, saving you time and improving your application's reliability. By applying this knowledge, you can enhance the resilience of your web applications and provide a more seamless experience to your users.</p>
<p>You also witnessed an example of Axios retry with exponential backoff with 3 retries. The reference code is on <a href="https://github.com/geshan/axios-retry">GitHub</a>. Then you knew about alternatives to Axios Retry and they are not as popular as Axios Retry.</p>
<p>So, the next time you find yourself wrestling with failed requests, remember to use Axios Retry and let it work its magic to bring reliability and resilience to your web development projects. Happy coding!</p>
How to Use LIMIT in Postgres Delete in two roundabout ways2023-09-14T11:47:52Zhttps://geshan.com.np/blog/2023/09/postgres-delete-limit/<p>Postgres is a very popular and feature-rich database. However, unlike other database management systems like MySQL, you cannot use the <code>LIMIT</code> keyword in Delete or Update statements. You can only use it in a select statement. In this blog post, you will learn about a couple of workarounds that can help delete rows on a Posgrest table with an arbitrary limit, let’s get going!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/postgres-delete-limit/01postgres-delete-limit.jpg" title="How to Use LIMIT in Postgres Delete in two roundabout ways" alt="How to Use LIMIT in Postgres Delete in two roundabout ways" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#the-example-quotes-schema">The example quotes schema</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#mysql-delete-allows-limit">MySQL Delete allows LIMIT</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#postgres-delete-does-not-allow-limit">Postgres Delete does not allow LIMIT</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#solution-1%3A-use-delete-with-where-in-and-select">Solution 1: Use DELETE with WHERE IN and SELECT</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#solution-2%3A-use-common-table-expression-(cte)">Solution 2: Use Common Table Expression (CTE)</a></li>
<li><a href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#conclusion">Conclusion</a></li>
</ul>
<h2 id="the-example-quotes-schema" tabindex="-1">The example quotes schema <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#the-example-quotes-schema">#</a></h2>
<p>For the scope of this blog post, you will use a simple schema with 2 tables, author and quote. This schema has been conveniently borrowed from another post on this blog about <a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/">Cascade delete in Postgres</a> database. The schema looks like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/02author-quotes-er.jpg" title="Entity relationship (ER) diagram of Author and Quotes relationship" alt="Entity relationship (ER) diagram of Author and Quotes relationship" />
<p>You can create the schema with the following create table statements:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> author <span class="token punctuation">(</span><br /> id <span class="token keyword">SERIAL</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span><br /> name <span class="token keyword">character</span> <span class="token keyword">varying</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span><br /> created_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span><br /> updated_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> quote <span class="token punctuation">(</span><br /> id <span class="token keyword">SERIAL</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span><br /> quote <span class="token keyword">character</span> <span class="token keyword">varying</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">UNIQUE</span><span class="token punctuation">,</span><br /> author_id <span class="token keyword">INTEGER</span> <span class="token keyword">REFERENCES</span> author<span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token keyword">ON</span> <span class="token keyword">DELETE</span> <span class="token keyword">CASCADE</span><span class="token punctuation">,</span><br /> created_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span><br /> updated_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>To insert some data you can run the following insert statements:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> author<span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <br /><span class="token punctuation">(</span><span class="token string">'Martin Fowler'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token string">'Bjarne Stroustrup'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token string">'John Johnson'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <br /> <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> quote <span class="token punctuation">(</span>quote<span class="token punctuation">,</span> author_id<span class="token punctuation">)</span> <span class="token keyword">VALUES</span><br /> <span class="token punctuation">(</span><span class="token string">'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'If you have to spend effort looking at a fragment of code and figuring out what it is doing, then you should extract it into a function and name the function after the "what".'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'There are only two kinds of languages: the ones people complain about and the ones nobody uses.'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'If you think it is simple, then you have misunderstood the problem.'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'First, solve the problem. Then, write the code.'</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Notice that if you delete the author all the related quotes will be deleted due to the ON DELETE CASCADE, which is discussed in the above-mentioned post. The create table will be pretty similar even in other flavors of databases like MySQL, which you are doing to know about next.</p>
<h2 id="mysql-delete-allows-limit" tabindex="-1">MySQL Delete allows LIMIT <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#mysql-delete-allows-limit">#</a></h2>
<p>Before you dive into how to achieve DELETE with LIMIT in Postgres, let's briefly mention that some database management systems, like MySQL, allow you to use the LIMIT clause directly with the DELETE statement. This can be quite convenient, as it allows you to limit the number of rows deleted in a single query. For example, if you want to delete only 1 quote by author ID 2 (Bjarne Stroustrup) from the above schema it can be done with the following query:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> quote <span class="token keyword">WHERE</span> author_id <span class="token operator">=</span> <span class="token number">2</span> <span class="token keyword">LIMIT</span> <span class="token number">1</span><span class="token punctuation">;</span></code></pre>
<p>In the above MySQL example, only 1 row that matches the author condition will be deleted. Unfortunately, Postgres does not offer this feature natively. In Postgres <a href="https://www.postgresql.org/docs/current/queries-limit.html">LIMIT</a> can only be used in Select statements. More on that in the next section.</p>
<h2 id="postgres-delete-does-not-allow-limit" tabindex="-1">Postgres Delete does not allow LIMIT <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#postgres-delete-does-not-allow-limit">#</a></h2>
<p>Postgres, a powerful and versatile relational database system, doesn't support the LIMIT clause directly in the DELETE statement. This can be a limitation when you want to delete a specific number of rows from a table without writing complex queries or scripts.</p>
<p>So, how can you achieve similar functionality in Postgres? Let's explore two common workarounds.</p>
<h2 id="solution-1%3A-use-delete-with-where-in-and-select" tabindex="-1">Solution 1: Use DELETE with WHERE IN and SELECT <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#solution-1%3A-use-delete-with-where-in-and-select">#</a></h2>
<p>One way to delete a limited number of rows in Postgres is by combining the DELETE statement with a WHERE condition that uses the IN clause along with a subquery. Here's how you can delete only 1 row for user id 2, similar to the above MySQL exmaple:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> quote <span class="token keyword">WHERE</span> id <span class="token operator">IN</span> <br /><span class="token punctuation">(</span><span class="token keyword">SELECT</span> id <span class="token keyword">FROM</span> quote <span class="token keyword">WHERE</span> author_id <span class="token operator">=</span> <span class="token number">2</span> <span class="token keyword">LIMIT</span> <span class="token number">1</span><span class="token punctuation">)</span></code></pre>
<p>In this example, you use a subquery to select the IDs of the rows from the quote table you want to delete, limiting the result set to 1 row. Then, you use the DELETE statement with a WHERE clause that specifies the IDs to delete. This effectively limits the number of rows deleted to 1 for the user id 2. It is more like <a href="https://ryanstutorials.net/linuxtutorial/piping.php#piping">piping</a> in bash where the output of one command is used as the input for the next command.</p>
<p>This approach provides a workaround to achieve the desired result, but it's essential to note that it may not be the most efficient solution for large tables. The subquery in the IN clause can impact performance, especially when dealing with extensive datasets. You will also need to think of the CASCADE effects where it might seem like only 1 row is being deleted but due to related rows and other rows related to the children's rows, it can delete 100s or 1000s of rows too. Next, you will learn about another solution to achieve limit while deleting records in Postgres.</p>
<h2 id="solution-2%3A-use-common-table-expression-(cte)" tabindex="-1">Solution 2: Use Common Table Expression (CTE) <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#solution-2%3A-use-common-table-expression-(cte)">#</a></h2>
<p>Another approach to achieving a limited DELETE operation in Postgres is by using a Common Table Expression (CTE). A CTE allows you to define a temporary result set that you can reference within your DELETE statement. Here's how you can use it to delete only 1 quote for author id 2:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">WITH</span> rows_to_delete <span class="token keyword">AS</span> <span class="token punctuation">(</span><br /> <span class="token keyword">SELECT</span> id<br /> <span class="token keyword">FROM</span> quote<br /> <span class="token keyword">WHERE</span> author_id<span class="token operator">=</span><span class="token number">2</span><br /> <span class="token keyword">LIMIT</span> <span class="token number">1</span><br /><span class="token punctuation">)</span><br /><span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> quote<br /><span class="token keyword">WHERE</span> id <span class="token operator">IN</span> <span class="token punctuation">(</span><span class="token keyword">SELECT</span> id <span class="token keyword">FROM</span> rows_to_delete<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In this solution, you first create a CTE called "rows_to_delete" that selects the IDs of the rows to be deleted, limited to 1 row for the author ID 2. Then, you use the DELETE statement with a WHERE clause that references the CTE to perform the deletion.</p>
<p>Using a CTE can be a more efficient and cleaner way to achieve the desired result compared to the subquery approach. It separates the query logic into distinct parts, making the query easier to read and maintain. The same logic of cascade delete applies to this method too. You can test it out on <a href="http://sqlfiddle.com/#!17/8bd76/1">SQLFiddle</a> too.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/09/postgres-delete-limit/#conclusion">#</a></h2>
<p>While Postgres does not provide a native LIMIT clause for the DELETE statement like some other database systems, you can still achieve the same functionality using workarounds. In this comprehensive exploration, you learned about two common methods: using DELETE with WHERE IN and SELECT and leveraging Common Table Expressions (CTEs). These techniques allow you to limit the number of rows deleted in a roundabout way, providing you with greater control over your data manipulation operations in Postgres.</p>
<p>Additionally, it's crucial to consider database design and indexing when dealing with large datasets to ensure efficient DELETE operations. Proper indexing and query optimization can significantly improve the performance of your database queries, including DELETE statements. You can use the same approach with Update statements too.</p>
<p>In conclusion, mastering these workarounds will empower you to efficiently manage your data in Postgres, even when faced with the absence of a native LIMIT clause in the DELETE statement. By understanding these techniques, you can make more informed decisions about how to manipulate your data effectively and efficiently in your Postgres database. Keep learning!</p>
Setting up environment variables in Docker Compose an almost complete guide2023-08-28T11:07:57Zhttps://geshan.com.np/blog/2023/08/docker-compose-environment-variables/<p>Docker Compose is a powerful tool for orchestrating multi-container applications. It allows software engineers to define and manage environment variables seamlessly. In the realm of modern software development and containerization, environment variables play a pivotal role in configuring applications and services. They offer a flexible way to manage settings, credentials, and other secret and dynamic values without hardcoding them into code. In this comprehensive guide, you will delve into the intricacies of setting up environment variables in Docker Compose, covering everything from the basics to best practices. Let's get going!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/docker-compose-environment-variables/01docker-compose-environment-variables.jpg" title="Setting up environment variables in Docker Compose an almost complete guide" alt="Setting up environment variables in Docker Compose an almost complete guide" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#prerequisites">Prerequisites</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#using-mysql-container-as-an-example">Using MySQL container as an example</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#how-to-define-environment-variables-in-docker-run">How to define environment variables in Docker run</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#adding-environment-variables-in-the-docker-compose-file">Adding environment variables in the Docker compose file</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#substitute-from-shell-or-env-file">Substitute from shell or .env file</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#pass-the-env-file-with---env-file-argument">Pass the env file with --env-file argument</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#putting-environment-variable-in-an-external-file">Putting environment variable in an external file</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#use-the-env_file-attribute">Use the env_file attribute</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#docker-compose-environment-variables-precedence">Docker compose environment variables precedence</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#best-practices-for-docker-compose-environment-variables">Best practices for Docker compose environment variables</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#conclusion">Conclusion</a></li>
</ul>
<h2 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#prerequisites">#</a></h2>
<p>Before you go to the code section, the following are some prerequisites:</p>
<ol>
<li>You have docker and docker-compose installed on your local machine. This post will make use of Docker 24.0.2 and docker-compose v 2.18.1 on a Mac. Docker compose can be run with <code>docker-compose</code> or <code>docker compose</code> command in this version of docker and docker-compose.</li>
<li>Prior experience with docker and docker-compose will be helpful.</li>
<li>Knowledge of MySQL and injecting environment variables will be useful but not necessary.</li>
</ol>
<p>For the context of this guide, you will use docker-compose in a development setting only. You are not expected to use docker-compose to orchestrate or scale containers. Scaling and orchestrating containers is done in a better way by Kubernetes. Given the requisites are mentioned, in the next section you will learn about MySQL container as an example for the whole post.</p>
<h2 id="using-mysql-container-as-an-example" tabindex="-1">Using MySQL container as an example <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#using-mysql-container-as-an-example">#</a></h2>
<p>For this post, you will use a MySQL 8.1 container as an example. You will first run the container without docker-compose and inject some environment variables. Then you will learn how to run the same MySQL container with docker compose and two main ways to inject those same environment variables.</p>
<h2 id="how-to-define-environment-variables-in-docker-run" tabindex="-1">How to define environment variables in Docker run <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#how-to-define-environment-variables-in-docker-run">#</a></h2>
<p>You can easily run a MySQL 8.1 container pulling the Docker image from DockerHub with the <a href="https://geshan.com.np/blog/2022/05/docker-commands/#docker-run">Docker run</a> command. First run <code>mkdir /tmp/mysql-data</code> to create a folder to hold the MySQL data then run the <code>docker run</code> command as follows:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> run <span class="token parameter variable">--name</span> mysql81 <span class="token parameter variable">--rm</span> <span class="token parameter variable">-v</span> /tmp/mysql-data:/var/lib/mysql <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_ROOT_PASSWORD</span><span class="token operator">=</span>mauFJcuf5dhRMQrjj <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_DATABASE</span><span class="token operator">=</span>testing <span class="token parameter variable">-p</span> <span class="token number">3306</span>:3306 <span class="token parameter variable">-it</span> mysql:8.1</code></pre>
<p>The parameters in the above docker run command are doing the following things:</p>
<ul>
<li>the option <code>--name</code> is used to assign the container the name "mysql8". If this option is not provided, Docker will assign a random name to the container</li>
<li>To ensure the container is removed when it stops, the --rm flag is utilized</li>
<li>A volume -v is attached to /tmp/mysql-data and /var/lib/mysql, ensuring that the data is retained between container restarts. However, this data will be removed when the host machine restarts, given its location in /tmp.</li>
<li>Environment variables -e are set to configure the MySQL instance. For instance, <code>MYSQL_ROOT_PASSWORD</code> is set to "mauFJcuf5dhRMQrjj" for the root user's password, and <code>MYSQL_DATABASE</code> is set to "testing" to initialize a database named "testing". This is the main focus here.</li>
<li>The option <code>-p 3306:3306</code> maps the host port 3306 to the container's port 3306. Port 3306 is MySQL's default port, and you can choose to map to a different host port, such as 3307:3306, which would link the local port 3307 to the container's port 3306.</li>
<li>The combination of -it ensures that the container runs interactively, allowing the display of all logs as a terminal is allocated. We're using the official MySQL image version 8.1.</li>
</ul>
<p>When it runs successfully it will show an output like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/docker-compose-environment-variables/02docker-run.jpg" title="Docker run with environment variables" alt="Docker run with environment variables" />
<p>If you want you can go into the container using the <a href="https://geshan.com.np/blog/2022/05/docker-commands/#docker-exec">docker exec</a> command.</p>
<h2 id="adding-environment-variables-in-the-docker-compose-file" tabindex="-1">Adding environment variables in the Docker compose file <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#adding-environment-variables-in-the-docker-compose-file">#</a></h2>
<p>You can run the same MySQL container much more easily, without the need to remember all the parameters more declaratively with a <code>docker-compose.yml</code> file which looks like the below:</p>
<pre class="language-bash"><code class="language-bash">version: <span class="token string">'3.8'</span><br />services:<br /> db:<br /> image: mysql:8.1<br /> cap_add:<br /> - SYS_NICE<br /> restart: always<br /> environment:<br /> - <span class="token assign-left variable">MYSQL_DATABASE</span><span class="token operator">=</span>quotes<br /> - <span class="token assign-left variable">MYSQL_ROOT_PASSWORD</span><span class="token operator">=</span>mauFJcuf5dhRMQrjj<br /> ports:<br /> - <span class="token string">'3306:3306'</span><br /> volumes:<br /> - db:/var/lib/mysql<br /> - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql<br />volumes:<br /> db:<br /> driver: <span class="token builtin class-name">local</span></code></pre>
<p>Here the environment variables are passed using the <code>environment</code> attribute. An init file is used to load the database with a sample quotes schema and some data, you can see the <a href="https://github.com/geshan/docker-compose-env-vars/blob/master/db/init.sql">file</a> and its content in this <a href="https://github.com/geshan/docker-compose-env-vars">GitHub repository</a>. You can learn more about <a href="https://geshan.com.np/blog/2022/02/mysql-docker-compose/#running-mysql-with-docker-compose">Docker-compose and MySQL</a> by reading this tutorial. For now, let's focus on the environment variable part.</p>
<p>As you can see above, the environment variables are part of the docker-compose file, and the sensitive variables are not replaced by another file or OS/shell variables. You will learn substitution in the next section.</p>
<h3 id="substitute-from-shell-or-.env-file" tabindex="-1">Substitute from shell or .env file <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#substitute-from-shell-or-.env-file">#</a></h3>
<p>To make the environment variables more obscure and not easily visible in the docker-compose.yml file you can substitute them. It can be substituted either from a <code>.env</code> file or from a shell variable. You can add a file named <code>.env</code> on the same level as your <code>docker-compose.yml</code> file with the following contents:</p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">MYSQL_DATABASE</span><span class="token operator">=</span>quotes<br /><span class="token assign-left variable">MYSQL_ROOT_PASSWORD</span><span class="token operator">=</span>mauFJcuf5dhRMQrjj</code></pre>
<p>Then you can change your docker-compose file to look like the below:</p>
<pre class="language-bash"><code class="language-bash">version: <span class="token string">'3.8'</span><br />services:<br /> db:<br /> image: mysql:8.1<br /> cap_add:<br /> - SYS_NICE<br /> restart: always<br /> environment:<br /> - <span class="token assign-left variable">MYSQL_DATABASE</span><span class="token operator">=</span><span class="token variable">${MYSQL_DATABASE}</span><br /> - <span class="token assign-left variable">MYSQL_ROOT_PASSWORD</span><span class="token operator">=</span><span class="token variable">${MYSQL_ROOT_PASSWORD}</span><br /> ports:<br /> - <span class="token string">'3306:3306'</span><br /> volumes:<br /> - db:/var/lib/mysql<br /> - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql<br />volumes:<br /> db:<br /> driver: <span class="token builtin class-name">local</span></code></pre>
<p>Now the variables <code>${MYSQL_DATABASE}</code> and <code>${MYSQL_ROOT_PASSWORD}</code> will be replaced by the values store in the <code>.env</code> file. You can check the final <code>docker-compose.yml</code> file that will be used for docker-compose commands by running <code>docker compose -f docker-compose-02-env-file.yml config</code> it will show you the compiled file as below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/docker-compose-environment-variables/03environment-attr.jpg" title="Docker compose environment variable substituted from file" alt="Docker compose environment variable substituted from file" />
<p>You can also set the variable as Shell variables and it will also be used. For example you can set the <code>MYSQL_DATABASE</code> variable to <code>test</code> by executing <code>export MYSQL_DATABASE=test</code>. After that if you run <code>docker compose -f docker-compose-02-env-file.yml config</code> you will see:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/docker-compose-environment-variables/04env-from-shell.jpg" title="Docker compose environment variable substituted from shell" alt="Docker compose environment variable substituted from shell" />
<p>In addition to the environment variables, you can also replace other things in the <code>docker-compose.yml</code> file with this pattern. For instance, if you want to put <code>image: mysql:{MYSQL_VERSION}</code> and get it replaced with a value from <code>.env</code> or shell variable it can be done too.</p>
<h3 id="pass-the-env-file-with---env-file-argument" tabindex="-1">Pass the env file with --env-file argument <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#pass-the-env-file-with---env-file-argument">#</a></h3>
<p>If you need to use a different set of environment variables for different environments on the fly then you can do it using <code>--env-file</code> argument with docker-compose commands. This will substitute the variable on the <code>docker-compose.yml</code> file for each command. Below is a <code>.env.test</code> file with the following variables:</p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">MYSQL_DATABASE</span><span class="token operator">=</span>quotes_test<br /><span class="token assign-left variable">MYSQL_ROOT_PASSWORD</span><span class="token operator">=</span>test</code></pre>
<p>To use this file while testing, you can use the command shown next:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> compose --env-file .env.test <span class="token parameter variable">-f</span> docker-compose-02-env-file.yml config </code></pre>
<p>It will use the <code>.env.test</code> file for the environment variables and the used <code>docker-compose.yml</code> file will look like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/docker-compose-environment-variables/05env-test-file.jpg" title="Docker compose environment variable substituted from test env file" alt="Docker compose environment variable substituted from test env file" />
<p>If you don’t want to list your environment variables in the <code>docker-compose.yml</code> file with the `environment1 attribute, that is possible. For that, you will need to use an external file, which will be elaborated in the next section.</p>
<h2 id="putting-environment-variable-in-an-external-file" tabindex="-1">Putting environment variable in an external file <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#putting-environment-variable-in-an-external-file">#</a></h2>
<p>You can put all your environment variables in an external file like a <code>.env</code> file. You can use the same <code>.env</code> file from the above example that has the <code>MYSQL_DATABASE</code> and <code>MYSQL_ROOT_PASSWORD</code> variables. To use this file to feed in the environment variable for the running docker container you will use the <code>env_file</code> <a href="https://docs.docker.com/compose/compose-file/05-services/#env_file">attribute</a>. It is discussed in the next section.</p>
<h3 id="use-the-env_file-attribute" tabindex="-1">Use the env_file attribute <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#use-the-env_file-attribute">#</a></h3>
<p>If you want you can also pass multiple files using the <code>env_file</code> attribute in docker-compose. To run the MySQL container with the <code>env_file</code> attribute, it will be changed to look as follows:</p>
<pre class="language-bash"><code class="language-bash"><span class="highlight-line">version: <span class="token string">'3.8'</span></span><br /><span class="highlight-line">services:</span><br /><span class="highlight-line"> db:</span><br /><span class="highlight-line"> image: mysql:8.1</span><br /><span class="highlight-line"> cap_add:</span><br /><span class="highlight-line"> - SYS_NICE</span><br /><span class="highlight-line"> restart: always</span><br /><span class="highlight-line"> env_file:</span><br /><mark class="highlight-line highlight-line-active"> - .env</mark><br /><mark class="highlight-line highlight-line-active"> ports:</mark><br /><span class="highlight-line"> - <span class="token string">'3306:3306'</span></span><br /><span class="highlight-line"> volumes:</span><br /><span class="highlight-line"> - db:/var/lib/mysql</span><br /><span class="highlight-line"> - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql</span><br /><span class="highlight-line">volumes:</span><br /><span class="highlight-line"> db:</span><br /><span class="highlight-line"> driver: <span class="token builtin class-name">local</span></span></code></pre>
<p>The file has been saved as <code>docker-compose-03-env-file-attr.yml</code> and you can check the final docker compose file with <code>docker compose -f docker-compose-03-env-file-attr.yml config</code>. It will look similar to the above file with the <code>environment</code> variable. But this one is taking the environment variables from an external file with the <code>env_file</code> attribute.</p>
<h2 id="docker-compose-environment-variables-precedence" tabindex="-1">Docker compose environment variables precedence <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#docker-compose-environment-variables-precedence">#</a></h2>
<p>There are multiple ways to pass the environment variables in docker compose. So an order is needed to decide what method takes precedence over the other. The priority is as follows:</p>
<ol>
<li>Configured via docker compose run -e in the <a href="https://docs.docker.com/compose/environment-variables/set-environment-variables/#set-environment-variables-with-docker-compose-run---env">command-line interface</a> (CLI).</li>
<li>Substituted from your <a href="https://docs.docker.com/compose/environment-variables/set-environment-variables/#substitute-from-the-shell">shell</a> environment variables.</li>
<li>Defined through the <a href="https://docs.docker.com/compose/environment-variables/set-environment-variables/#use-the-environment-attribute">environment attribute</a> in the Compose file.</li>
<li>Utilization of the --env-file <a href="https://docs.docker.com/compose/environment-variables/set-environment-variables/#substitute-with---env-file">argument</a> in the CLI.</li>
<li>Leverage of the env_file <a href="https://docs.docker.com/compose/environment-variables/set-environment-variables/#use-the-env_file-attribute">attribute</a> in the Compose file.</li>
<li>Establishment within an <a href="https://docs.docker.com/compose/environment-variables/set-environment-variables/#substitute-with-an-env-file">.env</a> file positioned at the root of your project directory.</li>
<li>Set within a container image utilizing the <a href="https://docs.docker.com/engine/reference/builder/#env">ENV</a> directive. Worth noting is that any ARG or ENV settings within a Dockerfile come into play only if no Docker Compose entries for environment, env_file, or run --env are present.</li>
</ol>
<p>So now you know that if you set a bash variable it will override setting the same environment variable on a file passed with <code>--env-file</code>. So be careful about the precedence of the variables to get your desired output.</p>
<p>All the examples of this post are in this <a href="https://github.com/geshan/docker-compose-env-vars">GitHub repository</a> for your reference. Some best practices regarding docker-compose environment variables are discussed next.</p>
<h2 id="best-practices-for-docker-compose-environment-variables" tabindex="-1">Best practices for Docker compose environment variables <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#best-practices-for-docker-compose-environment-variables">#</a></h2>
<p>Below are some best practices for using environment variables in a docker-compose file:</p>
<ul>
<li>Use environment variables to store sensitive data, such as passwords and API keys. This will help to keep your data secure and prevent it from being exposed. * Substitute them from the shell/OS environment variable on a docker-compose file.</li>
<li>Use a consistent naming convention for environment variables. This will make it easier to track and manage your environment variables.</li>
<li>Use a version control system to track changes to environment variables. This will help you to keep track of changes to your environment variables and identify any potential security vulnerabilities.</li>
<li>Use a secrets management tool to store sensitive data. This will help to keep your data secure and prevent it from being exposed.</li>
</ul>
<p>Those are some practices you should remember for docker-compose environment variables and environment variables in general.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/08/docker-compose-environment-variables/#conclusion">#</a></h2>
<p>In this guide, you learned how to put environment variables with a regular docker run command. Then you were guided to use environment variables with the <code>environment</code> attribute in a docker-compose file for a MySQL container. After that, you used some environment variable substitution from shell and <code>.env</code> files.</p>
<p>You also learned to use the <code>env_file</code> attribute of the docker-compose file to put the environment variables in an external file. Toward the end, you found out about the precedence of environment variables in docker-compose and finally learned some best practices for them.</p>
<p>I hope now you are more confident about using environment variables properly in the docker-compose context. Happy dockerizing your apps!</p>
A beginner's guide to type casting in TypeScript with examples2023-08-05T11:05:57Zhttps://geshan.com.np/blog/2023/08/typescript-cast/<p>TypeScript, known as a superset of JavaScript, is a powerful programming language that adds static typing to JavaScript. One essential aspect of TypeScript is type casting, also known as type assertions or type conversion, which allows developers to explicitly change the type of a value when needed. In this blog post, we will explore the concept of type casting in TypeScript, its usage, and best practices, supported by illustrative examples. Let's get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/typescript-cast/01typescript-cast.jpg" title="A beginner's guide to type casting in TypeScript with examples" alt="A beginner's guide to type casting in TypeScript with examples" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#typescript-intro">TypeScript Intro</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#popularity-of-typescript">Popularity of Typescript</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#type-casting-in-typescript">Type Casting in TypeScript</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#typescript-implicit-types">TypeScript Implicit Types</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#implicit-type-in-function-return-types">Implicit Type in Function Return Types</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#when-to-use-typescript-cast">When to Use TypeScript Cast</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#how-to-use-typescript-cast">How to Use TypeScript Cast</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#example-with-as">Example with as</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#example-using-angle-brackets">Example using Angle Brackets</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#when-to-choose-as-vs.-angle-brackets">When to Choose as vs. Angle Brackets</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#caution-about-type-casting-in-typescript">Caution about Type Casting in TypeScript</a></li>
<li><a href="https://geshan.com.np/blog/2023/08/typescript-cast/#conclusion">Conclusion</a></li>
</ul>
<h2 id="typescript-intro" tabindex="-1">TypeScript Intro <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#typescript-intro">#</a></h2>
<p>TypeScript is an open-source programming language developed by Microsoft that extends JavaScript by adding optional static typing. It is transpiled into plain JavaScript code and allows developers to catch type-related errors early during development.</p>
<p>By providing a way to specify types for variables, functions, and objects, TypeScript enhances code predictability and enables better tooling support. The TypeScript compiler checks the code for type correctness and offers better tooling support, making it easier to maintain and scale projects. In the next section, you will learn about the popularity of TypeScript over the years.</p>
<h2 id="popularity-of-typescript" tabindex="-1">Popularity of Typescript <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#popularity-of-typescript">#</a></h2>
<p>TypeScript has gained a lot of popularity in the past 10 years due to its many benefits over JavaScript. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. This means that you can use all of the features of JavaScript in TypeScript, but with the added benefits of type safety.</p>
<p>Compared to one of the few competitors of TypeScript like <a href="https://coffeescript.org/">CoffeeScript</a>, TypeScript has gained a lot of popularity. The below graph shows the popularity of TypeScript over the years.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/typescript-cast/02typescript-popularity.jpg" title="Popularity of TypeScript has soared significantly in the past 10 years" alt="Popularity of TypeScript has soared significantly in the past 10 years" />
<p>Next, you will learn about type casting in TypeScript.</p>
<h2 id="type-casting-in-typescript" tabindex="-1">Type Casting in TypeScript <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#type-casting-in-typescript">#</a></h2>
<p>Type casting, also known as type assertions or type conversion, is the process of explicitly informing the TypeScript compiler about the specific type of a value when it cannot be inferred automatically. In TypeScript, type casting is useful when working with variables whose type may change during runtime, or when we know more about a value's type than the compiler does.</p>
<h2 id="typescript-implicit-types" tabindex="-1">TypeScript Implicit Types <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#typescript-implicit-types">#</a></h2>
<p>Before diving into type casting, it's essential to understand TypeScript's implicit type inference. TypeScript automatically infers the type of variables based on their assigned values. For example:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> age <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript infers age as type number</span><br /><span class="token keyword">let</span> name <span class="token operator">=</span> <span class="token string">"John"</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript infers name as type string</span></code></pre>
<p>In the above example, TypeScript implicitly determines the types of age and name based on the values they are assigned.</p>
<h2 id="implicit-type-in-function-return-types" tabindex="-1">Implicit Type in Function Return Types <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#implicit-type-in-function-return-types">#</a></h2>
<p>TypeScript's implicit type inference is not limited to variables. It extends to function return types as well. When a function returns a value, TypeScript automatically infers the return type based on the function's implementation.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">a</span><span class="token operator">:</span> number<span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> a <span class="token operator">+</span> b<span class="token punctuation">;</span> <span class="token comment">// TypeScript infers the return type as number</span><br /><span class="token punctuation">}</span></code></pre>
<p>In this example, TypeScript infers that the return type of the add function is a number because the function returns the sum of two numbers.</p>
<h2 id="when-to-use-typescript-cast" tabindex="-1">When to Use TypeScript Cast <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#when-to-use-typescript-cast">#</a></h2>
<p>Type casting is used in various situations where the TypeScript compiler requires additional information about the type of a value. Some common scenarios include:</p>
<p>String Type to Return Type Conversion: When a function returns a value as a string, but you need to use it as a specific type, type casting can be utilized to convert the string to the desired type.</p>
<p>Type Safety and Type Guards: In cases where you want to narrow down a union type to a specific type (type guard), type casting assists in confirming the actual type of the value.</p>
<p>Working with Specific Types: When dealing with third-party libraries or external APIs, the returned values may not be typed correctly. Type casting enables developers to assert the correct types for these values.</p>
<p>In the following section, you will learn about how to use type casitng in TypeScript.</p>
<h2 id="how-to-use-typescript-cast" tabindex="-1">How to Use TypeScript Cast <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#how-to-use-typescript-cast">#</a></h2>
<p>TypeScript provides two primary methods for type casting: using the <code>as</code> keyword and using angle brackets (<>). Let's explore examples of both methods:</p>
<h3 id="example-with-as" tabindex="-1">Example with as <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#example-with-as">#</a></h3>
<p>Consider a scenario where a function returns a value as a string, but you need to treat it as a number for further calculations. The example might seem a bit force so you can focus on the syntax rather than the semantics. Here's how you can use as for type casting:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function</span> <span class="token function">multiply</span><span class="token punctuation">(</span>num1<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> num2<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span>num1 <span class="token operator">*</span> num2<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> convertedResult <span class="token operator">=</span> result <span class="token keyword">as</span> <span class="token builtin">number</span><span class="token punctuation">;</span><br /><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>convertedResult<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Output: 50</span></code></pre>
<p>In this example, the multiply function returns the result as a string, but we explicitly use the <code>as</code> keyword to cast it to the number type in the convertedResult variable.</p>
<p>Below is another example with a custom-defined type:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">type</span> <span class="token class-name">Person</span> <span class="token operator">=</span> <span class="token punctuation">{</span><br /> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span><br /> age<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">getPerson</span><span class="token punctuation">(</span>name<span class="token operator">:</span><span class="token builtin">string</span><span class="token punctuation">,</span> age<span class="token operator">:</span> Number<span class="token punctuation">)</span> <span class="token operator">:</span> Person <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">{</span><br /> name<span class="token punctuation">,</span><br /> age<br /> <span class="token punctuation">}</span> <span class="token keyword">as</span> Person<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">getPartialPerson</span><span class="token punctuation">(</span>name<span class="token operator">:</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">:</span> Partial<span class="token operator"><</span>Person<span class="token operator">></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">{</span><br /> name<br /> <span class="token punctuation">}</span> <span class="token keyword">as</span> Partial<span class="token operator"><</span>Person<span class="token operator">></span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">getCastedPerson</span><span class="token punctuation">(</span>age<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> Person <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">{</span><br /> age<br /> <span class="token punctuation">}</span> <span class="token keyword">as</span> Person<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> person <span class="token operator">=</span> <span class="token function">getPerson</span><span class="token punctuation">(</span><span class="token string">'John'</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// { name: 'John', age: 30 }</span><br /><br /><span class="token keyword">const</span> partialPerson <span class="token operator">=</span> <span class="token function">getPartialPerson</span><span class="token punctuation">(</span><span class="token string">'Jack'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>partialPerson<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// { name: 'Jack' }</span><br /><br /><span class="token keyword">const</span> castedPerson <span class="token operator">=</span> <span class="token function">getCastedPerson</span><span class="token punctuation">(</span><span class="token number">32</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>castedPerson<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// { age: 32 }</span></code></pre>
<p>In the above example, you can see a custom type called <code>Person</code> being defined with <code>name</code> as a string and <code>age</code> as a number. The first function <code>getPerson</code> sends back a full person type. You could have also made the age parameter a <a href="https://geshan.com.np/blog/2022/06/typescript-optional-parameters/">TypeScript optional parameter</a> with a default value of like 30.</p>
<p>The second example <code>getPartialPerson</code> sends only a partial type removing the name attribute from the <code>Person</code> type. The TypeScript <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype">Partial</a> utility type is also very useful in uniti testing scenario when you use a fixture which as a type. You can also utilize the <code>as unknown as Person</code> or your own type in the testing scenario to refrain from defining all the attributes for a type with a lot of attributes. Similar example can also be seen for <a href="https://geshan.com.np/blog/2022/07/jest-tohavebeencalledwith/#jest-tohavebeencalledwith-partial-array-and-object">partial array and object types with Jest</a>.</p>
<p>The last example named <code>getCastedPerson</code> supposedly sends back a Person type but as it is force cast the name is omitted and sends back an object with just the age. This is a forced type cast that does not comply with the defined type.</p>
<h3 id="example-using-angle-brackets" tabindex="-1">Example using Angle Brackets <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#example-using-angle-brackets">#</a></h3>
<p>Using angle brackets (<>) for type casting is an alternative method, although it is less commonly used due to possible conflicts with <a href="https://react.dev/learn/writing-markup-with-jsx">JSX syntax</a> if you are using TypeScript with a library like React. Here's the equivalent example using angle brackets:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function</span> <span class="token function">multiply</span><span class="token punctuation">(</span>num1<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> num2<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span>num1 <span class="token operator">*</span> num2<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> result<span class="token operator">:</span><span class="token builtin">string</span> <span class="token operator">=</span> <span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> convertedResult <span class="token operator">=</span> <span class="token operator"><</span><span class="token builtin">number</span><span class="token operator">></span>result<span class="token punctuation">;</span><br /><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>convertedResult<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Output: 50 not ‘50’</span></code></pre>
<p>Both methods achieve the same result, but using as is recommended for better compatibility and consistency in TypeScript code. Next, you wll know when to choose the <code>as</code> keyword vs. the angle brackets syntax.</p>
<h3 id="when-to-choose-as-vs.-angle-brackets" tabindex="-1">When to Choose as vs. Angle Brackets <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#when-to-choose-as-vs.-angle-brackets">#</a></h3>
<p>The as keyword and the angle brackets (<>) operator are both valid ways to perform type casting in TypeScript. However, there are some cases where one is preferable to the other.</p>
<p>The as keyword is generally preferred when you are sure of the type of the value you are casting. For example, if you know that the value of str is a string, you can safely use the as keyword to cast it to a number.</p>
<p>The angle brackets (<>) operator is generally preferred when you are not sure of the type of the value you are casting. For example, if you are receiving a value from an API, you might not know what type the value is. In this case, you can use the angle brackets (<>) operator to cast the value to a specific type.</p>
<h2 id="caution-about-type-casting-in-typescript" tabindex="-1">Caution about Type Casting in TypeScript <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#caution-about-type-casting-in-typescript">#</a></h2>
<p>While type casting is a powerful tool, it should be used with caution to avoid potential pitfalls. Some important considerations include:</p>
<ul>
<li>Compatibility: Ensure that the target type aligns with the actual value's type. Incorrect type casting may lead to runtime errors and unexpected behavior.</li>
<li>Type Guarding: Whenever possible, use type guards to narrow down the type of a value before resorting to type casting. Type guards enhance code safety and reduce the risk of errors.</li>
<li>Compiler Warnings: Be mindful of the TypeScript compiler warnings related to type casting. These warnings can help catch potential issues early on and improve code quality.</li>
</ul>
<p>Every tool comes with its one pros and cons and it applies to Type casting as well. Know the tradeoffs and don’t overuse type casting to the point that the whole Type system of TypeScript can feel dysfunctional. Use it optiamally and in the right ways.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/08/typescript-cast/#conclusion">#</a></h2>
<p>Type casting, or type assertions, in TypeScript allows developers to explicitly specify the type of a value when needed. By understanding how to use as and angle brackets for type casting, developers can enhance type safety and flexibility in their code. Remember to use type casting judiciously, and always consider other options such as type guards before resorting to explicit type conversions.</p>
<p>TypeScript's static typing and type casting capabilities offer significant advantages, making it a popular choice for building robust and scalable applications. As you continue to explore TypeScript, mastering type casting will undoubtedly strengthen your skills as a proficient TypeScript engineer, leading to more reliable and maintainable codebases.</p>
How to Use PostgreSQL COALESCE effectively with examples2023-07-29T10:45:52Zhttps://geshan.com.np/blog/2023/07/postgresql-coalesce/<p>In the world of database management systems, PostgreSQL (Postgres) is a popular choice due to its robust features and flexibility. One powerful function it offers is COALESCE, which allows you to handle null values effectively. In this blog post, you will explore what PostgreSQL COALESCE is, learn when it is useful, and see examples to demonstrate how to use it effectively. Let's get going!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/postgresql-coalesce/01postgresql-coalesce.jpg" title="How to Use PostgreSQL COALESCE effectively with examples" alt="How to Use PostgreSQL COALESCE effectively with examples" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#what-is-postgresql">What is PostgreSQL</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#postgresql-coalesce">PostgreSQL COALESCE</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#when-to-use-coalesce">When to Use COALESCE</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#how-to-use-postgresql-coalesce-with-examples">How to Use PostgreSQL COALESCE (with Examples)</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#replace-null-with-a-value">Replace null with a value</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#select-a-different-value-from-another-field">Select a different value from another field</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#replace-the-null-value-in-join-with-a-fallback-value">Replace the null value in join with a fallback value</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#conclusion">Conclusion</a></li>
</ul>
<h2 id="what-is-postgresql" tabindex="-1">What is PostgreSQL <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#what-is-postgresql">#</a></h2>
<p>PostgreSQL, often simply Postgres, is a free and open-source database management system (DBMS) with a long history of active development and a strong, proven feature set that has earned it a solid reputation for reliability, data integrity, and performance.</p>
<p>PostgreSQL is a true multi-user, multi-threaded database management system that can handle a wide range of workloads, from small personal databases to large, mission-critical applications. It supports a wide range of data types and operations, including full-text search, spatial data, and JSON data. It is also a <a href="https://arctype.com/blog/postgres-ordbms-explainer/">object-oriented</a> relational database management system.</p>
<p>PostgreSQL is also highly extensible, with a large community of developers contributing to the project. This means that there is a wide range of extensions available for PostgreSQL, covering everything from performance tuning to data modeling to security. You can know more about PostgreSQL in the video below (in just 100 seconds):</p>
<div style="position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%; margin-bottom: 1rem;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/n2Fluyr3lbc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;" allowfullscreen=""></iframe>
</div>
<p>There are many useful features of PostgreSQL, one of them is the built-in Coalesce function. It can be used while selecting data from table(s) which makes your life a lot easier. In the next section, you will learn what is Coalesce in PostgreSQL.</p>
<h2 id="postgresql-coalesce" tabindex="-1">PostgreSQL COALESCE <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#postgresql-coalesce">#</a></h2>
<p>COALESCE is a built-in function in Postgres that takes multiple arguments and returns the first non-null value from those arguments. It evaluates the arguments in the order specified and stops as soon as it encounters a non-null value. If all the arguments are null, COALESCE returns null. For example, if you have a column of values that are sometimes null, you can use COALESCE to return a default value for those null values.</p>
<p>COALESCE is a very useful function for dealing with null values in Postgres. It can be used to ensure that all values in a column are non-null or to return a default value for null values. In the next section, you will out in a bit more detail when to use COALESCE in PostgreSQL.</p>
<h2 id="when-to-use-coalesce" tabindex="-1">When to Use COALESCE <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#when-to-use-coalesce">#</a></h2>
<p>There are several scenarios where using COALESCE in PostgreSQL can be beneficial:</p>
<ul>
<li>
<p>Handling Null Values: When dealing with database queries or data manipulation, it's common to encounter null values. COALESCE helps you replace null values with alternative non-null values, making your queries or calculations more reliable and consistent.</p>
</li>
<li>
<p>Conditional Value Selection: COALESCE allows you to select a preferred value from a list of options based on specific conditions. This is especially useful when working with conditional logic in your queries with <code>SELECT COALESCE</code>.</p>
</li>
<li>
<p>Displaying Default Values: If you want to display a default value when a column contains a null value, COALESCE can be used to provide a fallback value for better data presentation.</p>
</li>
</ul>
<p>Next, you will learn about how to use the PostgreSQL COALESCE function with some examples.</p>
<h2 id="how-to-use-postgresql-coalesce-(with-examples)" tabindex="-1">How to Use PostgreSQL COALESCE (with Examples) <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#how-to-use-postgresql-coalesce-(with-examples)">#</a></h2>
<p>To demonstrate how to use COALESCE effectively, let's consider an example. Here is a simple <a href="https://www.lucidchart.com/pages/er-diagrams">ER-Diagram</a> of users and blog posts. One user can have 0 or more blog posts and one blog post will have exactly one author (user). It looks like the below as designed in <a href="https://dbdiagram.io/d/64c4f31602bd1c4a5ee64183">DB Diagram</a>:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/postgresql-coalesce/02postgresql-coalesce-erd.jpg" title="ER-Diagram with users and blog posts for PostgreSQL Coalesce examples" alt="ER-Diagram with users and blog posts for PostgreSQL Coalesce examples" />
<p>The above schema when exported to Postgres will result in something as follows:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token string">"users"</span> <span class="token punctuation">(</span><br /> <span class="token string">"id"</span> <span class="token keyword">serial</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span><br /> <span class="token string">"first_name"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"middle_name"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"last_name"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"role"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"created_at"</span> <span class="token keyword">TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token string">"blog_posts"</span> <span class="token punctuation">(</span><br /> <span class="token string">"id"</span> <span class="token keyword">serial</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span><br /> <span class="token string">"title"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"body"</span> <span class="token keyword">text</span><span class="token punctuation">,</span><br /> <span class="token string">"excerpt"</span> <span class="token keyword">text</span><span class="token punctuation">,</span><br /> <span class="token string">"user_id"</span> <span class="token keyword">integer</span><span class="token punctuation">,</span><br /> <span class="token string">"status"</span> <span class="token keyword">varchar</span><span class="token punctuation">,</span><br /> <span class="token string">"created_at"</span> <span class="token keyword">TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">ALTER</span> <span class="token keyword">TABLE</span> <span class="token string">"blog_posts"</span> <span class="token keyword">ADD</span> <span class="token keyword">FOREIGN</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token string">"user_id"</span><span class="token punctuation">)</span> <span class="token keyword">REFERENCES</span> <span class="token string">"users"</span> <span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Then you can add some data in these two tables executing the following INSERT statements:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> users <span class="token punctuation">(</span>first_name<span class="token punctuation">,</span> middle_name<span class="token punctuation">,</span> last_name<span class="token punctuation">,</span> role<span class="token punctuation">)</span> <br /><span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token string">'John'</span><span class="token punctuation">,</span> <span class="token string">'A'</span><span class="token punctuation">,</span> <span class="token string">'Doe'</span><span class="token punctuation">,</span> <span class="token string">'admin'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'Jane'</span><span class="token punctuation">,</span> <span class="token string">'B'</span><span class="token punctuation">,</span> <span class="token string">'Doe'</span><span class="token punctuation">,</span> <span class="token string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'John'</span><span class="token punctuation">,</span> <span class="token boolean">null</span><span class="token punctuation">,</span> <span class="token string">'White'</span><span class="token punctuation">,</span> <span class="token string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> blog_posts <span class="token punctuation">(</span>title<span class="token punctuation">,</span> body<span class="token punctuation">,</span> excerpt<span class="token punctuation">,</span> user_id<span class="token punctuation">,</span> <span class="token keyword">status</span><span class="token punctuation">)</span><br /><span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token string">'Hello World'</span><span class="token punctuation">,</span> <span class="token string">'This is my first post'</span><span class="token punctuation">,</span> <span class="token string">'This is my first post'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">'published'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'Hello Again'</span><span class="token punctuation">,</span> <span class="token string">'This is my second post'</span><span class="token punctuation">,</span> <span class="token string">'This is my second post'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">'published'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'Hello World2'</span><span class="token punctuation">,</span> <span class="token string">'This is my first post 1'</span><span class="token punctuation">,</span> <span class="token string">'This is my post'</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">'published'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'Hello Again2'</span><span class="token punctuation">,</span> <span class="token string">'This is my second post - draft'</span><span class="token punctuation">,</span> <span class="token boolean">null</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">'draft'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here you inserted 3 users, John Doe, Jane Doe, and John White. After that you inserted 4 blog posts 2 for John Doe and then the next 2 for John White. Notice that John While user no. 3 does not have a middle name and also has not written any blog posts. You will use this for the example queries. You can find the above schema and data set as a <a href="http://sqlfiddle.com/#!17/c72b73/25">SQL fiddle</a> if you want to try it on your own on the browser without the need to install anything.</p>
<p>You can also host the above database structure and data on a free hosted service like <a href="https://neon.tech/">Neon</a> or <a href="https://www.elephantsql.com/">Elephant SQL</a>. You can also opt to put it on your local machine as a <a href="https://geshan.com.np/blog/2021/12/docker-postgres/">Postgres Docker</a> container if you wish.</p>
<h3 id="replace-null-with-a-value" tabindex="-1">Replace null with a value <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#replace-null-with-a-value">#</a></h3>
<p>As the first example, your task is to select the “full name” of all the users. Now one (or more) of the users can have a <code>null</code> middle name as many people don’t have a middle name. In the data set “John Whilte” does not have a middle name so you can select the full name of all users with:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> <br />id<span class="token punctuation">,</span> CONCAT_WS<span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">,</span> first_name<span class="token punctuation">,</span> <span class="token keyword">COALESCE</span><span class="token punctuation">(</span>middle_name<span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span> last_name<span class="token punctuation">)</span> <br /><span class="token keyword">AS</span> full_name <span class="token keyword">FROM</span> users<span class="token punctuation">;</span></code></pre>
<p>Here you are using <code>CONCAT_WS</code> to concatenate the selected columns with a <code> </code> space in between. Then you are utilizing the handy <code>COALESCE</code> function for the middle name as it can be null, when the middle name is null you are selecting an empty string. This will result in the following which shows the full name of <code>John White</code> without any issues even when his middle name is null:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/postgresql-coalesce/03postgresql-coalesce-null-mn.jpg" title="PostgreSQL coalesce example of null middle name while selecting full name" alt="PostgreSQL coalesce example of null middle name while selecting full name" />
<p>Have a look at the third row in the result, the full name is as expected <code>John White</code> without any middle name.</p>
<h3 id="select-a-different-value-from-another-field" tabindex="-1">Select a different value from another field <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#select-a-different-value-from-another-field">#</a></h3>
<p>For the next example, in the <code>blog posts</code> table, the <code>excerpt</code> column can be <code>null</code>. So the task is, if the excerpt field is null then select the first x (say 5) characters from the body field. This can be done with:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span><br /> blog_posts<span class="token punctuation">.</span>id <span class="token keyword">as</span> blog_post_id<span class="token punctuation">,</span> <br /> first_name <span class="token keyword">as</span> author<span class="token punctuation">,</span> <span class="token keyword">COALESCE</span> <span class="token punctuation">(</span>excerpt<span class="token punctuation">,</span> <span class="token keyword">LEFT</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token keyword">FROM</span><br /> blog_posts <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> users <span class="token keyword">on</span> users<span class="token punctuation">.</span>id <span class="token operator">=</span> blog_posts<span class="token punctuation">.</span>user_id<span class="token punctuation">;</span></code></pre>
<p>This will result in:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/postgresql-coalesce/04postgresql-coalesce-excerpt.jpg" title="PostgreSQL coalesce example of selecting expert as the first 5 characters of the body" alt="PostgreSQL coalesce example of selecting expert as the first 5 characters of the body" />
<p>In the above query, you are using the <code>LEFT</code> function to select the first 5 characters of the body if the excerpt is null. This can be seen in the last row of the result which shows <code>This </code> those are the first 5 characters of the <code>body</code> column as the excerpt is null.</p>
<p>Another example of a similar task can be in the case of a product in an e-commerce store. The use-case is if the product is in discount select the <code>discounted_price</code> else select the <code>price</code> which is the regular price.</p>
<p>Coalesce can also be used with table joins, which you will learn next.</p>
<h3 id="replace-the-null-value-in-join-with-a-fallback-value" tabindex="-1">Replace the null value in join with a fallback value <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#replace-the-null-value-in-join-with-a-fallback-value">#</a></h3>
<p>The last task with the above data structure and the data set is to select all users and blog post titles even if the user does not have any blog posts. If the user does not have any blog post it should show <code>no title</code> for that user which will be the user id 2 with the name <code>Jane</code> in the above data set. It can be done with a left join as follows:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span><br /> users<span class="token punctuation">.</span>id<span class="token punctuation">,</span><br /> <span class="token keyword">COALESCE</span><span class="token punctuation">(</span>blog_posts<span class="token punctuation">.</span>title<span class="token punctuation">,</span> <span class="token string">'no title'</span><span class="token punctuation">)</span><br /><span class="token keyword">FROM</span><br /> users <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> blog_posts <span class="token keyword">on</span> users<span class="token punctuation">.</span>id <span class="token operator">=</span> blog_posts<span class="token punctuation">.</span>user_id</code></pre>
<p>The above query will result in:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/postgresql-coalesce/05postgresql-coalesce-left-join.jpg" title="PostgreSQL coalesce example of left join and replace missing value" alt="PostgreSQL coalesce example of left join and replace missing value" />
<p>The left join was used in the above query to list all the users even if the user did not have any blog posts. This is seen in the last row of the results. I hope the above 3 examples were useful to understand how to use PostgreSQL COALESCE.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/07/postgresql-coalesce/#conclusion">#</a></h2>
<p>PostgreSQL COALESCE function is a powerful function that allows you to handle null values effectively in your database queries. By using COALESCE function, you can replace null values, perform conditional value selection, and display default values as needed. Understanding and leveraging the capabilities of COALESCE enhances the reliability and readability of your SQL queries.</p>
<p>In this blog post, you learned the concept of PostgreSQL COALESCE and its applications. By incorporating COALESCE into your database operations, you can handle null values with ease and improve the accuracy of your data manipulations.</p>
<p>Remember to experiment with COALESCE in your own projects, exploring its versatility and finding creative ways to enhance your SQL queries. Happy coding with Postgres!</p>
How to undo a git rebase, a beginner's guide with an easy example2023-07-22T11:40:52Zhttps://geshan.com.np/blog/2023/07/undo-git-rebase/<p>Git is the most popular distributed version control system. It is very powerful and valuable too. Git Rebase is done when the main (master) branch has moved ahead and you need to apply the changes from the main branch to your branch while maintaining the history. In this post, you will learn how to undo a git-rebase. Let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/undo-git-rebase/01undo-git-rebase.jpg" title="How to undo a git rebase the easy way" alt="How to undo a git rebase the easy way" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#what-is-git-rebase%3F">What is Git Rebase?</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#when-you-would-need-to-undo-a-rebase">When You Would Need to Undo a Rebase</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#how-to-undo-a-git-rebase">How to Undo a Git Rebase</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#important-considerations">Important Considerations</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#conclusion">Conclusion</a></li>
</ul>
<h2 id="what-is-git-rebase%3F" tabindex="-1">What is Git Rebase? <a class="direct-link" href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#what-is-git-rebase%3F">#</a></h2>
<p>Git rebase is a way to rearrange your commits so that they appear in a linear history. This is useful when you want to integrate changes from multiple branches into a single branch, or when you want to fix a mistake in a commit. It is often used to integrate changes from one branch into another or to squash multiple commits into one.</p>
<p>When you rebase, Git takes the commits from your current branch and applies them on top of the tip of another branch. This means that the commits in your current branch will be rewritten to appear as if they were made on top of the other branch. Git rebase is a powerful tool that can help you keep your Git history clean and organized. It's a good idea to learn how to use it if you're working with git regularly.</p>
<p>Rebase can be a useful tool for keeping your Git history clean and organized. It can also be helpful for collaborating on projects with other people.</p>
<p>The most common use of rebase is to apply your commits (or changes) on top of a shared branch like master/main where other changes are coming in frequently. For instance, you started work on <code>your-feature-branch</code> 3 days back. You added 5 commits in the past 3 days but your teammates have merged 7 commits to the main/master branch. Now as it is time to open a pull/merge request you will apply 5 of your commits on top of the 7 merged commits. This is best done by rebasing <code>your-feature-branch</code> with the master branch before you open the pull/merge request.</p>
<p>Git rebase is also useful when you want to fix a mistake in a commit. Let's say you've made a <code>commit</code>, and then you realize that you made a mistake. You could delete the commit and make a new one, but this would lose your work.</p>
<p>A better way to fix a mistake is to use git rebase. With git rebase, you can edit the commit that you made a mistake in. This will create a new commit with the changes that you want to make. The old commit will still be there, but it will be marked as "rewritten."</p>
<p>Git rebase is a powerful tool that can help you to keep your Git history clean and organized. It's a good idea to learn how to use it if you're working with git regularly. But sometimes you will need to undo a rebase, you will know about some cases to undo a Git rebase in the next section.</p>
<h2 id="when-you-would-need-to-undo-a-rebase" tabindex="-1">When You Would Need to Undo a Rebase <a class="direct-link" href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#when-you-would-need-to-undo-a-rebase">#</a></h2>
<p>While git rebase can be a powerful tool, there are several scenarios where you might need to undo a rebase:</p>
<ul>
<li>
<p>Mistakenly Rebasing the Wrong Branch: If you accidentally rebase the wrong branch, it can lead to unintended changes and potential loss of work. Undoing the rebase becomes necessary to revert to the original state.</p>
</li>
<li>
<p>Unforeseen Issues in the Rebased Commits: Sometimes, after completing a rebase, you might realize that the changes introduced are problematic or introduce bugs. In such cases, you would want to undo the rebase and revert to the previous state.</p>
</li>
<li>
<p>Collaborative Workflows: When working collaboratively on a shared branch, if others have already based their work on the rebased branch, undoing the rebase can help avoid conflicts and maintain a consistent history.</p>
</li>
</ul>
<h2 id="how-to-undo-a-git-rebase" tabindex="-1">How to Undo a Git Rebase <a class="direct-link" href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#how-to-undo-a-git-rebase">#</a></h2>
<p>Depending on the stage of your Git rebase you will have to run different commands to undo or stop a rebase.</p>
<p>If you started a git rebase with <code>git rebase <branch-name></code> like <code>git rebase main</code> and you encountered a conflict and don’t want to solve the conflict, the easiest way to undo it at this point will be with:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> rebase abort</code></pre>
<p>The above command will abort the git rebase and you will go back to the original branch.</p>
<p>In case you have successfully done a git rebase with the main branch running <code>git rebase main</code>, then you will need to run a different set of commands. To switch the state of the branch back to before the rebase you can run:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> reset <span class="token parameter variable">--hard</span> ORIG_HEAD</code></pre>
<p>It is always advisable to make a backup of your branch before you do such commands with <code>git checkout -b <branch-name>-backup</code> to be safe if things do not go as expected. A more detailed way of doing it will be by using <a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-reflog">git reflog</a>.</p>
<p>Let's walk through the process in a bit more detail :</p>
<p>You can check out the <code>readme</code> branch after cloning the repository with <code>git checkout -b readme origin/readme</code>. The <code>readme</code> branch in this Nextjs weather app <a href="https://github.com/geshan/nextjs-weather-geo">repo</a> is behind the master branch. You can see the following view with <a href="https://www.atlassian.com/git/tutorials/git">gitk</a> or git log too.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/undo-git-rebase/02before-git-rebase.jpg" title="Readme branch before the git rebase" alt="Readme branch before the git rebase" />
<p>Now to rebase with the master branch you will run <code>git rebate master</code> on the <code>readme</code> branch.<br />
It will show the following output</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> rebase master<br />Successfully rebased and updated refs/heads/readme.</code></pre>
<p>Now if you look at the commit history with <code>gitk</code>, it will show the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/undo-git-rebase/03after-git-rebase.jpg" title="Readme branch after the git rebase with the master branch" alt="Readme branch after the git rebase with the master branch" />
<p>The <code>readme</code> branch has been rebased with the <code>master</code> branch, if you want to undo the rebase you should run:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> reset <span class="token parameter variable">--hard</span> ORIG_HEAD</code></pre>
<p>The above command will result in:</p>
<pre class="language-bash"><code class="language-bash">HEAD is now at 2ea1674 Better readme</code></pre>
<p>If you see the commit history now, you will see it the same as the previous git commit history which looks like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/undo-git-rebase/04after-undoing-git-rebase.jpg" title="Readme branch after undoing the git rebase" alt="Readme branch after undoing the git rebase" />
<p>Another way to rewrite the git commit history is by using <a href="https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/">git reflog</a> which is a very powerful tool to undo almost anything in Git. You can try <code>git reflog</code> on this branch and it will show all the changes including the rebase and undoing the rebase. In the next section, you will learn about some important considerations for undoing a git rebase.</p>
<h2 id="important-considerations" tabindex="-1">Important Considerations <a class="direct-link" href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#important-considerations">#</a></h2>
<p>While the steps outlined above will help you undo a git rebase, it's important to keep the following considerations in mind:</p>
<p>Collaboration and Shared Repositories: If you've pushed the rebased commits to a remote repository and others have based their work on it, undoing the rebase can lead to conflicts. Communicate with your team members and ensure everyone is aware of the changes you're making to maintain a consistent workflow.</p>
<p>Backup and Safety Measures: Creating a backup branch before undoing a rebase is crucial. It allows you to easily revert to the rebased state if needed. Additionally, consider creating a backup of your entire repository to have an extra layer of safety in case anything goes wrong during the undo process.</p>
<p>Review and Testing: After undoing a rebase, thoroughly review and test your code to ensure it functions as expected. It's possible that reverting the rebase might introduce other issues or conflicts that need to be addressed.</p>
<p>You can read about more <a href="https://geshan.com.np/blog/2014/07/4-git-tips-beyond-basics/">git tips</a> and also follow some simple rules to not encounter <a href="https://geshan.com.np/blog/2016/04/3-simple-rules-for-less-or-no-git-conflicts/">git conflicts</a>. Read both these posts and save yourself from common git related issues.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/07/undo-git-rebase/#conclusion">#</a></h2>
<p>Git rebase is a powerful feature that allows you to organize your commit history and create a cleaner workflow. However, there are situations where you might need to undo a git rebase. In this blog post, we explored what git rebase is, discussed scenarios where undoing a rebase becomes necessary, and provided a step-by-step guide on how to undo a git rebase effectively.</p>
<p>By incorporating the git reflog command into the process, you can easily identify the commit or reference to revert to, providing more flexibility and accuracy when undoing a rebase.</p>
<p>Remember, it's essential to carefully consider the implications of undoing a rebase, especially when collaborating with others or when the rebase has already been pushed to a remote repository. Always communicate with your team members and ensure a shared understanding of the Git workflow.</p>
<p>By understanding the process of undoing a git rebase, and utilizing the git reflog command, you can confidently manage your Git history and maintain a clean and organized repository. Happy coding and version controlling!</p>
How to craft your junior software engineer resume the right way2023-07-03T11:45:52Zhttps://geshan.com.np/blog/2023/07/junior-software-engineer-resume/<p>Writing a resume as a junior software engineer that strikes the right chord for both technical and non-technical readers is a crucial skill. In this guide, you will learn how you can craft a masterpiece junior software engineer that will get you more calls and possibly interviews, let’s get going!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/junior-software-engineer-resume/01junior-software-engineer-resume.jpg" title="How to write an impressive junior software engineer resume" alt="How to write an impressive junior software engineer resume" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#intro">Intro</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#slides">Slides</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#video">Video</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#6-seconds-test">6 seconds test</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#understand-the-hiring-funnel">Understand the hiring funnel</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#main-purpose-of-the-resume">Main purpose of the resume</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#taylor-your-resume-to-the-right-audience">Taylor your resume to the right audience</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#what-recruiters-look-for">What recruiters look for</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#guidelines-for-a-great-junior-software-engineer-resume">Guidelines for a great junior software engineer resume</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#xyz-formula">XYZ formula</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#no-typos-or-grammatical-errors">No Typos or grammatical errors</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#networking-is-critical">Networking is critical</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#contribute-to-open-source">Contribute to open source</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#sample-resume">Sample resume</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#how-to-get-work-experience-(internship)">How to get work experience (internship)</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#ambassador-programs">Ambassador programs</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#job-boards">Job boards</a></li>
<li><a href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#conclusion">Conclusion</a></li>
</ul>
<h2 id="intro" tabindex="-1">Intro <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#intro">#</a></h2>
<p>You have applied to 10s of jobs (maybe it is reaching 100 or more) but you have not got even 2 calls. That means a conversion (hit) rate of less than 2%. There are multiple reasons for this situation. You need to make your resume as sharp as a butcher’s knife, you cannot cut meat with a butter knife.</p>
<p>It is a topic that is near to my heart. I have previously written about <a href="https://geshan.com.np/blog/2018/09/7-practical-steps-to-land-your-first-tech-job/">5 practical steps to land your first tech job</a> and <a href="https://geshan.com.np/blog/2021/06/life-changing-side-project/">helped 10+ people find their first tech job in Australia</a> leveraging a side project. I had done a talk for an event on 24-Jun-2023 and below are the slides and the talk video from that event.</p>
<h2 id="slides" tabindex="-1">Slides <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#slides">#</a></h2>
<iframe src="https://docs.google.com/presentation/d/e/2PACX-1vQzwKBTbZ30JUjf5ZD16iRrOaqbxj-0oCTHKknP27ra8rUT6Nwfbw_NhN9J_D2UD0WjbqvsVYKOuJw0/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
<h2 id="video" tabindex="-1">Video <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#video">#</a></h2>
<p>The video of the talk is below:</p>
<div style="position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%; margin-bottom: 1rem;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/moP8Qjv9gaU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;" allowfullscreen=""></iframe>
</div>
<p>The text below is like an edited transcript of the talk video, you can extract the main points from the prose. Some of the content is tailored toward an Australian software engineering job seeker.</p>
<h2 id="6-seconds-test" tabindex="-1">6 seconds test <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#6-seconds-test">#</a></h2>
<p>With 10s or even 100s of applications flowing in, have you ever wondered how much time tech recruiters give for each resume or application? Recruiters typically spend only <a href="https://www.businessinsider.com/what-recruiters-look-at-on-your-resume-2014-11">6 seconds on average</a> looking at a resume as per eye-tracking software research before deciding whether to move forward with an applicant. This means that it is important to make sure that your resume is well-organized, easy to read, and highlights your skills and experience in a way that is relevant to the position you are applying for.</p>
<p>Make sure you make your resume 1 page for anyone with less than 5 years of experience and also put the most important part on the upper half of that page. With these facts in mind, it is essential to carefully craft your resume to make the best impression.</p>
<h2 id="understand-the-hiring-funnel" tabindex="-1">Understand the hiring funnel <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#understand-the-hiring-funnel">#</a></h2>
<p>Many junior engineers or those new to the job market may not be aware of the hiring funnel that leads to receiving a job offer. Initially, there are numerous applications for a job, but only some make it past the Application Tracking System (ATS) level to receive a recruiter call. If you're applying for a technical role, you may then be given a coding challenge, followed by a behavioral interview to assess your fit within the company and team.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/junior-software-engineer-resume/02hiring-funnel.jpg" title="Understand how the hiring funnel works and get around it" alt="Understand how the hiring funnel works and get around it" />
<p>Next, you'll likely have a technical interview, where more in-depth technical questions are asked. Once you've successfully cleared all these steps, you may receive a job offer. In some cases, a reference check step may be required before the offer is made. It's important to note that the sequence of these steps may vary depending on the company.</p>
<p>The hiring funnel is designed to filter applicants, and only a select few will receive job offers in the end. Therefore, it's crucial to craft your resume in a way that helps you stand out and secure that initial recruiter call.</p>
<p>In the next section, you will know about the main purpose of the resume.</p>
<h2 id="main-purpose-of-the-resume" tabindex="-1">Main purpose of the resume <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#main-purpose-of-the-resume">#</a></h2>
<p>It's a common misconception that a resume should be long and filled with everything you know. However, the primary purpose of your resume is actually to get a call from the recruiter. While it's crucial to showcase your technical abilities and skills, you should prioritize making a strong impression within the first few seconds of the recruiter's review.</p>
<blockquote>
<p>Think of your resume's primary goal as persuading the recruiter to call you for an initial interview.</p>
</blockquote>
<p>Any secondary purposes should be considered after ensuring that your resume is designed to achieve this main objective.</p>
<p>When redesigning your resume, keep in mind that your primary goal is to make an impact within the seven or eight seconds the recruiter spends reviewing it. Focus on crafting a junior software engineer resume that will entice the recruiter to call you for an interview.</p>
<p>To get the call from the tech recruiter as a junior software engineer, your resume contents will not only need to be tailored for the job but also adjusted precisely for the audience. You will learn about that in the following segment.</p>
<h2 id="taylor-your-resume-to-the-right-audience" tabindex="-1">Taylor your resume to the right audience <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#taylor-your-resume-to-the-right-audience">#</a></h2>
<p>It's also essential to understand your resume's target audience. The first person, or potentially a machine, to review your resume will likely be a recruiter or talent acquisition professional. They will only spend a few seconds deciding if you're a candidate worth calling, so make sure your resume is tailored to capture their attention quickly.</p>
<blockquote>
<p>Ensure that your resume effectively showcases your abilities within the limited time a recruiter spends reviewing it.</p>
</blockquote>
<p>Even with a single-page resume, consider what's immediately visible and whether it helps persuade the recruiter to call you.</p>
<p>After the initial review process, other professionals like senior engineering managers, VP of Engineering, or CTOs at smaller companies may examine your resume from a more technical perspective. While it's important to include technical details, avoid overloading your resume with jargon, as it may not be useful for the talent acquisition person.</p>
<blockquote>
<p>Striking the right balance between showcasing your technical abilities and maintaining clarity is essential for creating an effective resume.</p>
</blockquote>
<p>When crafting your resume, it's important to maintain a balance that addresses both the recruiter and technical professionals who may review it later.</p>
<p>As you are now aware that the primary audience of the resume is a tech recruiter, let’s find out what they look for in a resume in the preceding section.</p>
<h2 id="what-recruiters-look-for" tabindex="-1">What recruiters look for <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#what-recruiters-look-for">#</a></h2>
<p>I conducted some written interviews from 2019-202 with some in-house tech recruiters in Sydney. From interviews conducted between 2019 and 2022, here's what recruiters look for in a resume:</p>
<p><a href="https://geshan.com.np/blog/2019/01/things-tech-recruiters-look-for/#clo%C3%AB-stanbridge-(safety-culture)-looks-for-tech-and-soft-skills">Cloë</a> emphasizes the importance of including side projects, particularly for junior engineers who may have limited industry experience. Showcasing side projects allow you to demonstrate your skills, share your code, and provide a working URL, which can help you stand out and prove your abilities beyond your primary job experience.</p>
<p><a href="https://geshan.com.np/blog/2020/08/things-tech-recruiters-look-for-in-your-resume-first-interview-part-02/#scott-crowe-(canva)-looks-for-relevant-experience-and-technical-capability">Scott</a> from Canva highlights another important aspect recruiters look for in a resume: interest in the product and good business acumen. As a software engineer, it's essential to understand how the business makes money and be knowledgeable about the product or company you're applying to. This shows that you're not just a developer working in isolation but rather a team player who understands the bigger picture.</p>
<p><a href="https://geshan.com.np/blog/2022/08/what-do-tech-recruiters-look-for-part-03/#pam-(harrison.ai)-focuses-on-the-previous-workplaces-and-tech-stacks-used">Pam</a> from Harrison AI emphasizes the importance of having an organized and clean CV. Ensuring your resume is free from typos and grammatical mistakes not only creates a positive first impression but also highlights your communication and organizational skills.</p>
<p>Taking all these factors into account, there are some guidelines for creating a great resume. The golden standard is to have a one-page resume. If you have only two or three years of experience, a three-page resume may be excessive. Aim for conciseness and clarity while including all relevant information.</p>
<p>In the next section, you will learn about the guidelines for a superb junior software engineer resume.</p>
<h2 id="guidelines-for-a-great-junior-software-engineer-resume" tabindex="-1">Guidelines for a great junior software engineer resume <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#guidelines-for-a-great-junior-software-engineer-resume">#</a></h2>
<p>Creating a concise and impactful resume is an art. When writing each sentence, weigh its importance and consider your audience and purpose: will this help you get a call within the crucial first few seconds? Aim for a one-page resume that effectively showcases your skills in just a few seconds.</p>
<p>Think of your resume as a collection of pixels, and use the available space wisely. While some whitespace is necessary for readability, too much can detract from the content. Even professionals with 15+ years of experience can craft a one-page resume that effectively highlights their accomplishments. Remember, it's about quality, not quantity.</p>
<p>Prominent figures like Marissa Mayer of Yahoo, <a href="https://enhancv.com/resume-examples/famous/mark-zuckerberg/#famous-resume">Mark Zuckerberg</a>, and Andy Jassy’s (CEO of AWS) resumes can fit on just one page. If their resume can fit on a page, anyone with a few years of experience can certainly create a one-page resume as well.</p>
<blockquote>
<p>The key is to be ruthless in selecting content – ask yourself if each piece of information is relevant and necessary. If not remove it.</p>
</blockquote>
<p>To create an effective resume, ensure it's concise and focused on securing the initial recruiter's call. Include vital information such as your contact details (email and phone number), making them clickable or tappable for added convenience. Also, add links to relevant social profiles like GitHub, LinkedIn, and your personal blog if you have one, as these showcase your skills and communication abilities.</p>
<p>Incorporating side projects with working URLs can make a significant difference, particularly for the technical audience who will review your resume later. For example, if a junior engineer's resume includes a side project with a working URL, it demonstrates their skills beyond their primary job experience, enhancing their chances of being called for an interview.</p>
<p>When faced with the challenge of fitting your resume into a single page, prioritize the most important aspects of your experience and skills. By focusing on what truly matters and cutting out irrelevant details, you can create a concise, impactful resume that will grab the attention of recruiters.</p>
<h3 id="xyz-formula" tabindex="-1">XYZ formula <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#xyz-formula">#</a></h3>
<p>To write a resume that gets calls, follow the <a href="https://www.inc-aus.com/bill-murphy-jr/google-recruiters-say-these-5-resume-tips-including-x-y-z-formula-will-improve-your-odds-of-getting-hired-at-google.html">XYZ formula</a> when describing your job experience and achievements: "Accomplished X measured by Y doing Z." This formula helps showcase the impact of your work and the methods you used. However, it's essential to strike a balance. For example, if you have five points in a job description, use the XYZ formula for three of them and describe the other two in a more straightforward manner.</p>
<blockquote>
<p>Finding the right balance between showcasing your accomplishments and providing clear information is crucial.</p>
</blockquote>
<p>Many junior software engineer resumes tend to include only straightforward descriptions, but incorporating the XYZ formula can help your resume stand out and increase your chances of getting calls from recruiters. Write about the impact and how you have saved cost or helped the business earn more money. For example, if you have worked on a project that has saved the company $10,000, mention it in your resume. This will help you stand out from other candidates.</p>
<p>If you have a line in your entry-level software engineer resume like "Worked closely with business analysts, etc.," you could ask <a href="https://bard.google.com/">Bard</a> to rewrite it using the XYZ formula. The AI tool may not provide a perfect conversion, but it can offer valuable pointers and hints for making your resume more impactful and audience-friendly. By incorporating AI assistance and following the previously mentioned tips, you can create a resume that stands out and increases your chances of receiving calls from recruiters.</p>
<h3 id="no-typos-or-grammatical-errors" tabindex="-1">No Typos or grammatical errors <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#no-typos-or-grammatical-errors">#</a></h3>
<p>Remember to keep your resume up-to-date and free from typos or grammatical mistakes. In 2023, consider using AI-powered tools, such as ChatGPT or Google's Bard, to fine-tune your resume. While you shouldn't rely solely on an AI tool to create your entire resume, it can be helpful in refining your content.</p>
<h3 id="networking-is-critical" tabindex="-1">Networking is critical <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#networking-is-critical">#</a></h3>
<p>Another essential tip for increasing your chances of getting noticed is networking. It is not something you put directly in your resume but it helps a lot to find your first junior software engineer job.</p>
<blockquote>
<p>Your network is your net worth, so try to find someone who can refer you to a company.</p>
</blockquote>
<p>Referrals offer two main benefits:</p>
<ol>
<li>They can help you bypass the ATS (Application Tracking System), avoiding the "black hole" where your resume might be lost without ever being seen.</li>
<li>The person referring you may receive a referral bonus, creating a win-win situation for both parties if you're hired and stay with the company for a certain period.</li>
</ol>
<p>Leveraging your network and referrals can significantly improve your chances of landing a job and ensure your resume gets the attention it deserves.</p>
<p>Networking is crucial for expanding your professional connections and increasing your chances of landing a job. To expand your network, attend relevant meetups. In 2023, meetups are back in full swing, with events happening frequently in various cities. Look for events that align with your interests, such as Python meetups or other tech-related gatherings.</p>
<blockquote>
<p>When attending meetups, set simple goals, like adding three new connections on LinkedIn at each event.</p>
</blockquote>
<p>With consistent networking, you can significantly expand your professional circle within months. This increases the likelihood of finding job opportunities through your connections.</p>
<p>In addition to attending meetups, make good use of LinkedIn, join communities, and consider helping to organize events. These activities can further broaden your network and improve your chances of finding job openings through referrals and connections.</p>
<p>Expanding on networking strategies, consider reverse searching recruiters from your target companies and roles, and connect with them on LinkedIn. Have a list of companies you want to work for and start building connections with their recruiters. This proactive approach can increase your chances of being noticed by the right people.</p>
<h3 id="contribute-to-open-source" tabindex="-1">Contribute to open source <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#contribute-to-open-source">#</a></h3>
<p>Volunteer experience, such as contributing to open-source projects or participating in events, can be valuable additions to your resume, especially if you lack professional experience.</p>
<blockquote>
<p>Contributions to well-known projects in your field can significantly enhance your profile.</p>
</blockquote>
<p>In the next section, you will see a sample resume (template) that works and gets the job done.</p>
<h2 id="sample-resume" tabindex="-1">Sample resume <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#sample-resume">#</a></h2>
<p>The sample resume provided demonstrates a good balance of different elements, such as the XYZ formula, straightforward job descriptions, and quantifiable achievements. While you may not always have specific numbers available, use tools to gather data and showcase your accomplishments. Be honest and ensure you can confidently explain these achievements during an interview.</p>
<p>When listing skills on your resume, it's essential to provide context. Avoid using word clouds or a simple list of skills without explaining how you have applied them in your work.</p>
<blockquote>
<p>For example, if you mention Docker, Git, or other tools, it's helpful to explain where and when you used these technologies, as opposed to simply listing them.</p>
</blockquote>
<p>Providing context makes it easier for the recruiter to understand your capabilities and how you have used your skills in the past.</p>
<blockquote>
<p>You can find the sample in this <a href="https://docs.google.com/document/d/19ZxyQ4WVJzMsXTL2kL4s6Lb9-4ESfEYTldxOUQZtzdo/edit?usp=sharing">Google Doc</a>.</p>
</blockquote>
<p>The resume template provided has been successfully used by over 30 individuals to secure their first tech jobs in Australia, demonstrating its effectiveness. Remember, striking a balance between your technical skills and interpersonal qualities in your resume can make you a more well-rounded candidate, increasing your chances of landing the desired role.</p>
<p>You might be in a catch-22 situation of the job first or work experience first. You can get some work experience/internship following some tips listed in the section below.</p>
<h2 id="how-to-get-work-experience-(internship)" tabindex="-1">How to get work experience (internship) <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#how-to-get-work-experience-(internship)">#</a></h2>
<p>If you're facing the challenge of having no work experience or internships, it's essential to find alternative ways to showcase your skills and capabilities. This can include side projects, volunteering, or personal initiatives that demonstrate your technical abilities and problem-solving skills.</p>
<p>To overcome the challenge of not having work experience or internships, one solution is to start your own side project.</p>
<blockquote>
<p>No one is stopping you from pursuing a project that showcases your skills and interests. Bring in some friends and collaborate on a project together.</p>
</blockquote>
<p>Initiating and working on side projects can be a valuable way to demonstrate your abilities, creativity, and initiative to potential employers, even in the absence of traditional work experience.</p>
<p>If you're concerned about the costs of starting a side project, don't worry. As a student, you can take advantage of resources like the <a href="https://education.github.com/pack">GitHub Student Developer Pack</a>, which offers numerous free services, including domain registration and CI/CD pipelines.</p>
<blockquote>
<p>Other platforms, like <a href="https://www.theforage.com/">Forage</a> and <a href="https://www.entrylevel.net/">Entry Level</a>, provide virtual work experience opportunities.</p>
</blockquote>
<p>Programs like <a href="https://www.startmate.com/student-fellowship">Startmate Student Fellowship</a> and job seekers' groups on platforms like Slack can also be helpful resources.</p>
<p>When applying for internships and early career opportunities, it's important to remember that some roles may prioritize behavioral aspects over technical expertise. In such cases, you can showcase your adaptability, teamwork, and interpersonal skills to demonstrate how you can fit into the group.</p>
<blockquote>
<p>Emphasize your willingness to learn and grow with the company, as this can be a valuable trait for organizations looking to invest in potential future leaders.</p>
</blockquote>
<p>Additionally, participate in <a href="https://www.hackathonsaustralia.com/past-hackathons">hackathons</a>, attend conferences (many offer scholarships or free tickets for students), and network by volunteering at events. These experiences can help expand your network and contribute valuable content to your resume.</p>
<p>Stay connected to the tech community and explore community job boards and professional groups on platforms like Slack. By leveraging these resources, networking, and focusing on your resume's purpose and audience, you can create a strong resume and increase your chances of landing a job in the tech industry.</p>
<h3 id="ambassador-programs" tabindex="-1">Ambassador programs <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#ambassador-programs">#</a></h3>
<p>To boost your resume, consider participating in ambassador programs from big tech companies,</p>
<blockquote>
<p>such as <a href="https://developers.google.com/community/gdsc">Google Developer Student Clubs</a>, <a href="https://education.github.com/experts">GitHub Campus Experts</a>, <a href="https://students.stackoverflow.co/">Stack Overflow Student Ambassdor</a> and <a href="https://studentambassadors.microsoft.com/">Microsoft student ambassador</a> programs.</p>
</blockquote>
<p>These connections demonstrate your involvement in the tech community and add credibility to your resume.</p>
<p>Next, you will learn about some job boards and a couple of them will be focused on early career professionals like yourself.</p>
<h2 id="job-boards" tabindex="-1">Job boards <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#job-boards">#</a></h2>
<p>Explore various job boards and communities focused on different aspects of the tech industry.</p>
<blockquote>
<p><a href="https://au.gradconnection.com/">GradConnection</a> by Seek is specifically tailored for graduate and internship roles, while <a href="https://www.earlywork.co/community">Early Work</a> has a Slack community with job postings.</p>
</blockquote>
<p><a href="https://au.mystartupgig.com/jobs">My Startup Gig</a> is another job board suitable for junior or entry-level individuals, as startups often provide rapid learning opportunities and may be more willing to hire those with less experience.</p>
<p>Consider connecting with local startup communities and hubs, like <a href="https://fishburners.org/">Fishburners</a> and Microsoft Reactor, for networking and job search resources. For women seeking a more female-friendly work environment, the <a href="https://work180.com/en-au/for-women/job-search">Work 180</a> job board is worth checking out.</p>
<p>By utilizing these resources and actively participating in the tech community, you can increase your chances of finding the right job opportunities and making valuable connections in the industry.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/07/junior-software-engineer-resume/#conclusion">#</a></h2>
<p>By following these tips and tactics, you can significantly improve your chances of landing a job through effective networking and a well-crafted resume. You have got multiple tips about how to structure your resume, what to delete, and things to highlight.</p>
<p>You have also been made aware of the superpower of networking and how to push the other knobs of volunteering, ambassador programs, and finding jobs on job boards. I hope you crack your first tech role soon and break into tech faster. It might just be your key to a better life. Best of luck!</p>
How to use environment variables in Next.js (includes a working example app)2023-06-29T11:45:52Zhttps://geshan.com.np/blog/2023/06/nextjs-env-variables/<p>Next.js is a React framework that makes building fast, user-friendly websites easy. It uses server-side rendering to pre-render pages on the server, which makes them load faster for users. Environment variables are a way to store sensitive information, such as passwords or API keys, outside of your code. This makes it more secure, it is one of the tenants of the <a href="https://12factor.net/config">12-factor app</a>. In this post, you will learn how to properly use environment variables on both the server and client side of Next.js. Let’s get started!</p>
<!-- more -->
<img class="center" src="https://geshan.com.np/images/nextjs-env-variables/01nextjs-env-variables.jpg" title="Learn how use Next.js environment variables the easy way" alt="Learn how use Next.js environment variables the easy way" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#table-of-contents">Table of contents</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#popularity-of-next.js">Popularity of Next.js</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#environment-variables">Environment variables</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#environment-variables-in-next.js">Environment variables in Next.js</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#nextjs-browser-level-environment-variables">Next.js browser level environment variables</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#environment-variable-load-order-in-next.js">Environment variable load order in Next.js</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#example-city-weather-app">Example city weather app</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#city-weather-next.js-app-code">City weather Next.js app code</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#conclusion">Conclusion</a></li>
</ul>
<h2 id="popularity-of-next.js" tabindex="-1">Popularity of Next.js <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#popularity-of-next.js">#</a></h2>
<p>Next.js is a fast, scalable, and easy-to-use React framework that can be used to build static, dynamic, and server-side rendered applications. It is popular for its static site generation, server-side rendering, routing, pre-rendering, and SEO features. Some of its competitors are Nuxt.js, Gatsby, and Remix.<br />
Next.js is the most popular React.js meta framework if you look at the search trends on Google for the last 5 years.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nextjs-env-variables/02nextjs-popularity.jpg" title="Next.js is the most popular React meta framwork" alt="Next.js is the most popular React meta framwork" />
<p>Next, you will learn about environment variables and their use in web applications.</p>
<h2 id="environment-variables" tabindex="-1">Environment variables <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#environment-variables">#</a></h2>
<p>Environment variables are a set of variables that are used to store information about the environment in which a web application is running. They are defined in a key and value pair. This information can include things like the path to the application's files, the name of the database, and the port number that the application is listening on.</p>
<p>Environment variables are often used to configure applications, and they can also be used to store data that needs to be accessed by multiple parts of an application.</p>
<p>Environment variables can be a powerful tool for configuring and managing web applications. By understanding how they work, you can use them to make your applications more flexible and easier to maintain. For example, below is a sample <code>.env</code> file used for an application’s environment variables:</p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">DB_HOST</span><span class="token operator">=</span><span class="token number">127.0</span>.0.1<br /><span class="token assign-left variable">DB_NAME</span><span class="token operator">=</span>blog<br /><span class="token assign-left variable">DB_USERNAME</span><span class="token operator">=</span>blogger<br /><span class="token assign-left variable">DB_PASSWORD</span><span class="token operator">=</span>O7HEzAM<span class="token variable">$o7p2u5lw7g</span><br /><span class="token assign-left variable">DB_PORT</span><span class="token operator">=</span><span class="token number">3306</span><br /><span class="token assign-left variable">DB_URL</span><span class="token operator">=</span>mysql://<span class="token variable">$DB_USER</span><span class="token builtin class-name">:</span><span class="token variable">$DB_PASSWORD</span>@<span class="token variable">$DB_HOST</span><span class="token builtin class-name">:</span><span class="token variable">$DB_PORT</span>/<span class="token variable">$DB_NAME</span></code></pre>
<p>With the above environment variables in a <code>.env</code> file or as operating system-level environment variables, you can choose the database you want. For instance, on staging it will point to a staging database and for a production environment, the production database credentials will be used.<br />
One more thing to notice above is the <code>DB_URL</code> which is constructed by referencing the other variables with a <code>$</code> sign.</p>
<p>Next.js will automatically expand the variables using $ to <a href="https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#referencing-other-variables">reference</a> other variables, so it will construct a valid <code>DB_URL</code> replacing the right environment variables.<br />
In the next section, you will learn about Next.js environment variables.</p>
<h2 id="environment-variables-in-next.js" tabindex="-1">Environment variables in Next.js <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#environment-variables-in-next.js">#</a></h2>
<p>For this post, you will use Next.js 13 with the <a href="https://nextjs.org/docs/app/building-your-application">app router</a> (not the pages folder). To use environment variables in Next.js, you can create a <code>.env.local</code> file in your project’s root directory. This file will contain all of your environment variables, which you can then access in your code using the process.env object while doing backend execution or server-side components.<br />
For example, if you have an environment variable called SECRET_KEY, you can access it in your code like this:</p>
<pre class="language-bash"><code class="language-bash">const secretKey <span class="token operator">=</span> process.env.SECRET_KEY<span class="token punctuation">;</span></code></pre>
<p>You can also use environment variables to set up different configurations for your website. For example, you could create an environment variable called PRODUCTION that you set to true when your website is live. This would allow you to use different settings for your production website than you would for your development website. You can read more about this in the official <a href="https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#loading-environment-variables">docs</a>.</p>
<h3 id="next.js-browser-level-environment-variables" tabindex="-1">Next.js browser level environment variables <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#next.js-browser-level-environment-variables">#</a></h3>
<p>At times you will need to expose some variables to be accessible on the frontend at the browser level. Of course, these variables cannot be secret (like a password) as they can be read by everyone as it is part of the frontend code.</p>
<p>Let’s say if you want to use Google Analytics 4 then you will need to expose the GA4 measurement ID to the browser.<br />
To expose a public environment variable in Next.js you have to prefix the environment variable with <code>NEXT_PUBLIC</code>, so for the GA4 measurement ID it can be exposed as follows:</p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">NEXT_PUBLIC_GA_MEASUREMENT_ID</span><span class="token operator">=</span><span class="token string">"<your-GA4-ID-here>"</span></code></pre>
<p>You will know about the load order for environment variables in Next.js in the next section.</p>
<h3 id="environment-variable-load-order-in-next.js" tabindex="-1">Environment variable load order in Next.js <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#environment-variable-load-order-in-next.js">#</a></h3>
<p>The environment variables have a precedence order in Next.js which is as below:</p>
<ol>
<li>process.env</li>
<li>.env.$(NODE_ENV).local</li>
<li>.env.local (Not checked when NODE_ENV is <code>test</code>.)</li>
<li>.env.$(NODE_ENV)</li>
<li>.env</li>
</ol>
<p>For <code>NODE_ENV</code> the only allowed values are development, production, and test. In case of the precedence, if NODE_ENV is <code>development</code> and you define a variable say <code>DB_HOST</code> in both <code>.env.development.local</code> and <code>.env</code>, the value in .<code>env.development.local</code> will be used as per above priority order.<br />
You have learned about Next.js environment variables, now it is time to the knowledge into practice in the following section with an example app.</p>
<h2 id="example-city-weather-app" tabindex="-1">Example city weather app <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#example-city-weather-app">#</a></h2>
<p>To put the things you have learned about Next.js environment variables you will clone and run an example app that can show the temperature of a given city. The application has two parts. The first part to call an API with an API key to get the weather for a city will use a server-only environment variable.</p>
<p>Then the second part is adding Google Analytics 4 script to the application which will use the public (frontend/browser) level environment variable.<br />
The running app looks like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nextjs-env-variables/03nextjs-app-running.jpg" title="Next.js city weather app running on Vercel" alt="Next.js city weather app running on Vercel" />
<p>As you can see, it is a stock Next.js app <a href="https://nextjs.org/docs/getting-started/installation#automatic-installation">installed</a> with <code>npx create-next-app@latest</code>. It does not use Typescript and Tailwind but it does use the new app router and EsLint. To come to the above stage, the following two Next.js environment variables have been used:</p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">API_NINJAS_API_KEY</span><span class="token operator">=</span><span class="token string">"API_NINJAS_API_KEY-value"</span><br /><span class="token assign-left variable">NEXT_PUBLIC_GA_MEASUREMENT_ID</span><span class="token operator">=</span><span class="token string">"G-**--------"</span></code></pre>
<p>You can understand what is happening in the application by having a look at the visual representation of the communication flow between the systems involved as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/nextjs-env-variables/04nextjs-app-architecture.jpg" title="Next.js city weather app talking with API Ninjas API and Google Analytics" alt="Next.js city weather app talking with API Ninjas API and Google Analytics" />
<p>When the user hits the URL with (or without the city), the Next.js app will send a request to <a href="https://api-ninjas.com/">API Ninjas</a> with the API key provided (for free) by API Ninjas. This app calls the API Ninjas’ <a href="https://api-ninjas.com/api/weather">weather API</a> sending the city name. If no city name is given it falls back to London.</p>
<p>If you put the API Key from API Ninjas in public other people can use it and/or abuse it as well. That is why it is set as a server-level Next.js environment variable. For your app to work you will also need to register and get your own free API key from API Ninjas.</p>
<p>Another system involved is Google Analytics. A GA4 tag is added to the weather app that will report the page views to Google Analytics. It used the measurement ID to identify the app. You can follow this <a href="https://hackernoon.com/setting-up-google-analytics-4-in-a-nextjs-project">tutorial</a> to get a step-by-step process to add GA4 on a Next.js app.</p>
<p>The goal of this guide is to explain the Next.js environment variables. As the GA4 script runs on the browser level the measurement id environment variable is set to <code>NEXT_PUBLIC</code> so that it can be used on the frontend/browser. This environment variable can be exposed to the public.</p>
<p>The app is deployed on Vercel currently, you can also use <a href="https://geshan.com.np/blog/2023/01/nextjs-docker/">Next.js with Docker</a> to run the app locally. With Docker, you can easily run any Next.js application without the need to have a specified version of Node.js or NPM. These dependencies can be configured as code in the Dockerfile.</p>
<h3 id="city-weather-next.js-app-code" tabindex="-1">City weather Next.js app code <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#city-weather-next.js-app-code">#</a></h3>
<p>The code of the stock Next.js starter template has been changed a bit to add a server call to API Ninjas and also add the Google Analytics 4 script on the page. You will need to know how Next.js works as a prerequisite. All the code changes have been done to the <code>src/app/page.js</code> file which looks like the below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Image <span class="token keyword">from</span> <span class="token string">'next/image'</span><span class="token punctuation">;</span><br /><span class="token keyword">import</span> styles <span class="token keyword">from</span> <span class="token string">'./page.module.css'</span><span class="token punctuation">;</span><br /><span class="token keyword">import</span> Script <span class="token keyword">from</span> <span class="token string">'next/script'</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token constant">GA_MEASUREMENT_ID</span> <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NEXT_PUBLIC_GA_MEASUREMENT_ID</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getWeatherData</span><span class="token punctuation">(</span><span class="token parameter">city</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.api-ninjas.com/v1/weather?city=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>city<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'X-API-Key'</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">API_NINJAS_API_KEY</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><br /> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <br /> data<span class="token punctuation">.</span>city <span class="token operator">=</span> city<span class="token punctuation">;</span><br /> <br /> <span class="token keyword">return</span> data<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">Home</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> city <span class="token operator">=</span> req<span class="token punctuation">.</span>searchParams<span class="token punctuation">.</span>city <span class="token operator">||</span> <span class="token string">'London'</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> weatherData <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getWeatherData</span><span class="token punctuation">(</span>city<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span><br /> <span class="token operator"><</span>main className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>main<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>description<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>p<span class="token operator">></span><br /> Current temperature <span class="token keyword">in</span> <span class="token punctuation">{</span>weatherData<span class="token punctuation">.</span>city<span class="token punctuation">}</span> is <br /> <span class="token operator"><</span>code className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>code<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span>weatherData<span class="token punctuation">.</span>temp<span class="token punctuation">}</span> <span class="token constant">C</span><span class="token operator"><</span><span class="token operator">/</span>code<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br /> <span class="token operator"><</span>div<span class="token operator">></span><br /> <span class="token operator"><</span>a<br /> href<span class="token operator">=</span><span class="token string">"https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"</span><br /> target<span class="token operator">=</span><span class="token string">"_blank"</span><br /> rel<span class="token operator">=</span><span class="token string">"noopener noreferrer"</span><br /> <span class="token operator">></span><br /> By<span class="token punctuation">{</span><span class="token string">' '</span><span class="token punctuation">}</span><br /> <span class="token operator"><</span>Image<br /> src<span class="token operator">=</span><span class="token string">"/vercel.svg"</span><br /> alt<span class="token operator">=</span><span class="token string">"Vercel Logo"</span><br /> className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>vercelLogo<span class="token punctuation">}</span><br /> width<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">100</span><span class="token punctuation">}</span><br /> height<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">24</span><span class="token punctuation">}</span><br /> priority<br /> <span class="token operator">/</span><span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>center<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>Image<br /> className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>logo<span class="token punctuation">}</span><br /> src<span class="token operator">=</span><span class="token string">"/next.svg"</span><br /> alt<span class="token operator">=</span><span class="token string">"Next.js Logo"</span><br /> width<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">180</span><span class="token punctuation">}</span><br /> height<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">37</span><span class="token punctuation">}</span><br /> priority<br /> <span class="token operator">/</span><span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>grid<span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token operator"><</span>Script<br /> src<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://www.googletagmanager.com/gtag/js?id=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">GA_MEASUREMENT_ID</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><br /> strategy<span class="token operator">=</span><span class="token string">"afterInteractive"</span><br /> <span class="token operator">/</span><span class="token operator">></span><br /> <span class="token operator"><</span>Script id<span class="token operator">=</span><span class="token string">"google-analytics"</span> strategy<span class="token operator">=</span><span class="token string">"afterInteractive"</span><span class="token operator">></span><br /> <span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><br /> window.dataLayer = window.dataLayer || [];<br /> function gtag(){window.dataLayer.push(arguments);}<br /> gtag('js', new Date());<br /> gtag('config', '</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">GA_MEASUREMENT_ID</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">');<br /> </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><br /> <span class="token operator"><</span><span class="token operator">/</span>Script<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>main<span class="token operator">></span><br /> <span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>The change to this <code>src/app/page.js</code> are as follows:</p>
<ul>
<li>The <code>Script</code> tag has been imported from <code>next/script</code> on line no 3</li>
<li>On the line 4, You have also assigned the Next.js environment variable <code>NEXT_PUBLIC_GA_MEASUREMENT_ID</code> to a constant called <code>GA_MEASUREMENT_ID</code></li>
<li>From lines 6-17, the getWeatherData async function uses fetch to call the API Ninjas’ weather API passing the city that is passed in as a parameter to the function. It returns the data received from the API call after adding the city to it. This function runs on the server and it used the <code>API_NINJAS_API_KEY</code> Next.js environment variable to make the call to the API.</li>
<li>In the Home component, <code>city</code> is fetched from the URL query parameter if it exists else the city variable gets a fallback value of <code>London</code> on line 20.</li>
<li>On line 21, the <code>getWeatherData</code> function is called with the city constant set on line 20.</li>
<li>The name of the city and the current temperature in that city are rendered, on lines 24-28</li>
<li>On lines 60-71, the GA4 tag is placed which uses the public Next.js environment variable twice. Once for the Google tag manager and again at line 69 for the GA config.</li>
</ul>
<p>With these changes now you have used both the server side and client (browser) side Next.js environment variable in a small but useful and working application. All the code is available in the public <a href="https://github.com/geshan/nextjs-weather-geo/tree/master">GitHub repository</a>.</p>
<p>You can easily deploy this app on Vercel by clicking the “Deploy” button on the readme or find it running on <a href="https://nextjs-weather-geo.vercel.app/?city=Sydney">Vercel</a>. You can clone/fork the repo and change the to fit your needs.</p>
<p>Hurray! You have learned how to use the Next.js environment variable with the help of an example working app that fetches the live weather for any given city and sends back analytics to GA 4.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/06/nextjs-env-variables/#conclusion">#</a></h2>
<p>In this guide, you learned about Next.js and its popularity. Then you also gained some knowledge about environment variables for web applications and specifically for Next.js. After that, you learned both types of Next.js environment variables (server and client ones which are public) and the order of precedence to use them.</p>
<p>Then you looked at an example of a Next.js app that pulls in the current weather for any given city using both server-level and client/browser-level environment variables.</p>
<p>I hope you learned something new, keep absorbing more knowledge. If you have any questions or comments please leave them below.</p>
A beginner's guide to running Elasticsearch with Docker and Docker Compose2023-06-08T12:45:52Zhttps://geshan.com.np/blog/2023/06/elasticsearch-docker/<p>Elasticsearch is one of the most popular open-source software to store, search and analyze large amounts of data with very fast response times. If you're venturing into the world of Elasticsearch, you may have heard about Docker and Docker Compose as convenient ways to manage and deploy your applications. In this beginner's guide, we'll walk you through the process of running Elasticsearch using these powerful containerization tools. Let's get started!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/elasticsearch-docker/01elasticsearch-docker.jpg" title="Learn how to run Elasticsearch with Docker and Docker Compose" alt="Learn how to run Elasticsearch with Docker and Docker Compose" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#table-of-contents">Table of contents</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#what-is-elasticsearch">What is Elasticsearch?</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#why-use-elasticsearch">Why Use Elasticsearch?</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#popularity-of-elasticsearch">Popularity of Elasticsearch</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#faceted-search-with-elasticsearch-is-useful-for-e-commerce">Faceted search with Elasticsearch is useful for e-commerce</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#run-elasticsearch-with-docker">Run Elasticsearch with Docker</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#run-elasticsearch-with-docker-compose">Run Elasticsearch with Docker Compose</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#load-product-data-on-elasticsearch">Load product data on Elasticsearch</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#search-for-a-product-on-elasticsearch">Search for a product on Elasticsearch</a></li>
<li><a href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#conclusion">Conclusion</a></li>
</ul>
<!-- tocstop -->
<h2 id="what-is-elasticsearch%3F" tabindex="-1">What is Elasticsearch? <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#what-is-elasticsearch%3F">#</a></h2>
<p><a href="https://www.elastic.co/elasticsearch/">Elasticsearch</a> is a powerful, open-source search and analytics engine built on top of the Apache Lucene library. It provides a distributed, scalable, and high-performance platform for storing, searching, and analyzing data in real time. With Elasticsearch, you can quickly index large volumes of data and retrieve relevant information using complex queries. Its versatility makes it suitable for a wide range of use cases, including logging, monitoring, and e-commerce applications.</p>
<p>In the next section, you will learn about the reasons to use Elasticsearch.</p>
<h2 id="why-use-elasticsearch%3F" tabindex="-1">Why Use Elasticsearch? <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#why-use-elasticsearch%3F">#</a></h2>
<p>Before you delve into the technical details, let's briefly explore the reasons why Elasticsearch is popular among software engineers and organizations:</p>
<ul>
<li>Full-Text Search: Elasticsearch excels at full-text search, enabling users to search for and retrieve specific words or phrases within vast amounts of unstructured data.</li>
<li>Scalability: Elasticsearch is designed to be distributed, allowing you to scale horizontally by adding more nodes to your cluster, resulting in increased performance and capacity.</li>
<li>Real-Time Analytics: With Elasticsearch, you can perform real-time analytics on your data, gaining valuable insights and visualizations for monitoring and decision-making purposes.</li>
<li>Easy Integration: Elasticsearch integrates seamlessly with various programming languages, libraries, and tools, making it an accessible choice for developers across different ecosystems.</li>
</ul>
<p>In the subsequent section, you will know about how popular Elasticsearch is and the big names that use it.</p>
<h2 id="popularity-of-elasticsearch" tabindex="-1">Popularity of Elasticsearch <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#popularity-of-elasticsearch">#</a></h2>
<p>Elasticsearch has experienced a remarkable surge in popularity in recent years, becoming one of the most widely adopted open-source search and analytics engines. One key factor contributing to its popularity is its ability to handle and process large volumes of data at an unprecedented speed. Whether it's ingesting, indexing, or searching data, Elasticsearch delivers exceptional performance and scalability.</p>
<p>With this optimal blend of features, speed, performance and scalability Elasticsearch has risen in popularity in the past 5 years. It is the most popular software when it comes to searching large volumes of data with super fast responses leaving its competition like Solr and OpenSearch behind. This can be seen clearly in the <a href="https://trends.google.com/trends/explore?date=2018-08-05%202023-01-06&q=Elasticsearch,opensearch,solr,algolia&hl=en">Google Trends chart</a> below for the past 5 years.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/elasticsearch-docker/02elasticsearch-popularity.jpg" title="Elasticsearh has been much more popular than other competitors like Solr in the past 5 years" alt="Elasticsearh has been much more popular than other competitors like Solr in the past 5 years" />
<p>It might be a surprise for you that <a href="https://www.elastic.co/customers/success-stories?usecase=enterprise-search&industry=All">big names</a> like <a href="https://netflixtechblog.com/tagged/elasticsearch">Netflix</a>, <a href="https://www.elastic.co/videos/ebay-and-elasticsearch-this-is-not-small-data">Ebay</a>, <a href="https://www.elastic.co/videos/how-booking-com-is-tackling-unparalleled-growth-complexity-and-scale-with-elastic">Booking.com</a>, <a href="https://www.elastic.co/elasticon/tour/2018/santa-clara/elastic-at-adobe-making-search-smarter-with-machine-learning-at-scale">Adobe</a>, and <a href="https://www.elastic.co/customers/github">GitHub</a> as some of the companies that use Elasticsearch to meet their demanding search needs.</p>
<p>It is also used by many E-commerce companies to enhance their search and especially make the faceted search better. You are going to learn a bit more about faceted search in E-commerce and Elasticsearch next.</p>
<h2 id="faceted-search-with-elasticsearch-is-useful-for-e-commerce" tabindex="-1">Faceted search with Elasticsearch is useful for e-commerce <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#faceted-search-with-elasticsearch-is-useful-for-e-commerce">#</a></h2>
<p><a href="https://www.coveo.com/blog/faceted-search/">Faceted search</a> is a powerful feature provided by Elasticsearch that greatly enhances the search experience in e-commerce applications. It allows users to narrow down their search results by providing intuitive and interactive filtering options based on different attributes or facets of the products. This capability not only improves the usability of the search functionality but also enables customers to quickly find the products they are looking for, leading to higher conversion rates and customer satisfaction.</p>
<p>In an e-commerce context, products typically have various attributes such as brand, category, price range, size, color, and more. Faceted search leverages these attributes to offer customers a rich filtering experience. For example, imagine a user searching for a pair of shoes. With faceted search, they can easily refine their search results by selecting specific attributes like brand (Nike, Adidas, etc.), category (running shoes, sneakers), size (9, 10, etc.), and color (black, white, red). Each selected facet narrows down the search results in real time, providing an interactive and personalized shopping experience.</p>
<p>Faceted search also helps customers discover new products or make more informed purchase decisions. By exposing different facets and their corresponding values, customers can explore various options and compare products based on their preferences. They can, for instance, filter products by customer ratings, price ranges, or availability to find the best fit for their needs. This not only simplifies the decision-making process but also empowers customers with more control over their shopping experience.</p>
<p>Moreover, faceted search is not limited to a single attribute or facet. Elasticsearch allows you to define multiple facets and their hierarchies. For instance, in the case of clothing, you can have facets for gender, category, brand, and size. This hierarchical approach enables customers to drill down into specific subcategories or attributes while refining their search. It provides a structured and organized way to navigate through a vast product catalog, making it easier for customers to locate specific products or explore related options.</p>
<p>Faceted search with Elasticsearch offers numerous benefits for e-commerce applications. It improves the search experience by providing interactive and intuitive filtering options, allowing customers to narrow down their search results based on different attributes. It enhances product discovery and enables customers to make more informed purchase decisions. By empowering users with control over their search and offering a personalized shopping experience, faceted search contributes to increased customer satisfaction, improved conversion rates, and ultimately, the success of e-commerce businesses.</p>
<p>Now that you understand the significance of Elasticsearch and facets in searching, let's explore how to run it using Docker and Docker Compose.</p>
<h2 id="run-elasticsearch-with-docker" tabindex="-1">Run Elasticsearch with Docker <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#run-elasticsearch-with-docker">#</a></h2>
<p>Docker provides a platform for packaging applications and their dependencies into lightweight, portable containers. This blog has other posts on docker like <a href="https://geshan.com.np/blog/2023/01/nextjs-docker/">Next.js and Docker</a>, <a href="https://geshan.com.np/blog/2022/02/mysql-docker-compose/">MySQL and Docker</a> to name a couple. This containerization approach allows you to isolate your Elasticsearch instance, making it easy to manage and deploy across different environments.</p>
<p>To run Elasticsearch with Docker, follow these steps:</p>
<p>If you haven't already, <a href="https://docs.docker.com/engine/install/">install Docker</a> on your system by following the official installation instructions for your operating system.</p>
<p>Open your terminal or command prompt and run the following command to pull the official Elasticsearch Docker image version 8.8.0, the latest one at the time of writing this post:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> pull elasticsearch:8.8.0</code></pre>
<p>This will pull the Elasticsearch version 8.8.0 from <a href="https://hub.docker.com/_/elasticsearch">DockerHub</a>, the official Elastic website guide pulls it from the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html">Elastic.co docker registry</a>. It will look like the below when the image is pulled (downloaded) to your machine:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/elasticsearch-docker/03elasticsearch-docker-pull.jpg" title="Output of docker pull for elasticsearch image from Docker hub" alt="Output of docker pull for elasticsearch image from Docker hub" />
<p>Once the image is downloaded, run the following command to start an Elasticsearch container:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> run <span class="token parameter variable">--rm</span> <span class="token parameter variable">--name</span> elasticsearch_container <span class="token parameter variable">-p</span> <span class="token number">9200</span>:9200 <span class="token parameter variable">-p</span> <span class="token number">9300</span>:9300 <span class="token parameter variable">-e</span> <span class="token string">"discovery.type=single-node"</span> <span class="token parameter variable">-e</span> <span class="token string">"xpack.security.enabled=false"</span> elasticsearch:8.8.0</code></pre>
<p>This command starts a container named elasticsearch_container, maps Elasticsearch ports 9200 and 9300 to the host machine, and sets the discovery type to single-node. It also sets the security to false as you don’t want to use HTTPs white testing locally. These settings are suited only for local development and not for production deployment. Here port 9200 is used to hit the Elasticsearch REST API and 9300 is used to communicate between nodes. As this is a single node setup for local you can also opt to not expose the port 9300.</p>
<p>Congratulations! You now have a running Elasticsearch instance using Docker. It will look like the following when the command executes after showing a lot of logs:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/elasticsearch-docker/04elasticsearch-docker-run.jpg" title="Output of docker run for elasticsearch" alt="Output of docker run for elasticsearch" />
<p>You can stop the container by hitting <code>Ctrl+C</code>. However, using Docker Compose can simplify the process and allow you to define your Elasticsearch configuration more conveniently as discussed next.</p>
<h2 id="run-elasticsearch-with-docker-compose" tabindex="-1">Run Elasticsearch with Docker Compose <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#run-elasticsearch-with-docker-compose">#</a></h2>
<p>Docker Compose is a tool for defining and running multi-container Docker applications. It enables you to specify your Elasticsearch configuration, including environment variables, network settings, and volumes, in a declarative YAML file. Let's see how to set up Elasticsearch using Docker Compose:</p>
<p>If Docker Compose is not already installed on your system, refer to the <a href="https://docs.docker.com/compose/install/">official Docker Compose documentation</a> for installation instructions.</p>
<p>Create a new file named docker-compose.yml and open it in a text editor. Add the following content to the file:</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span><br /><span class="token key atrule">services</span><span class="token punctuation">:</span><br /> <span class="token key atrule">elasticsearch</span><span class="token punctuation">:</span><br /> <span class="token key atrule">image</span><span class="token punctuation">:</span> elasticsearch<span class="token punctuation">:</span>8.8.0<br /> <span class="token key atrule">ports</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> 9200<span class="token punctuation">:</span><span class="token number">9200</span><br /> <span class="token punctuation">-</span> 9300<span class="token punctuation">:</span><span class="token number">9300</span><br /> <span class="token key atrule">environment</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> discovery.type=single<span class="token punctuation">-</span>node<br /> <span class="token punctuation">-</span> xpack.security.enabled=false</code></pre>
<p>This configuration sets up an Elasticsearch service, exposes ports 9200 and 9300, and sets the discovery type to single-node. As done in the above docker run command it also sets the security to false so that you don’t need to deal with any SSL for the tests you will do in the next section.</p>
<p>To start Elasticsearch with Docker Compose, in your terminal or command prompt, navigate to the directory containing the docker-compose.yml file, and run the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker-compose</span> up</code></pre>
<p>This command starts the Elasticsearch container defined in the Docker Compose file. If you want to run in detached mode add -d to run it as a background process. The above command will show the following output:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/elasticsearch-docker/05elasticsearch-docker-compose-up.jpg" title="Output of docker-compose up for Elasticsearch" alt="Output of docker-compose up for Elasticsearch" />
<p>Now you have Elasticsearch running using Docker Compose, providing a more streamlined approach to managing your Elasticsearch environment. In the next section, you wil add a test product to your Elasticsearch running with docker-compose.</p>
<h2 id="load-product-data-on-elasticsearch" tabindex="-1">Load product data on Elasticsearch <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#load-product-data-on-elasticsearch">#</a></h2>
<p>To test your Elasticsearch setup and explore its capabilities for e-commerce search, it's helpful to load sample product data into the system. Elasticsearch provides a powerful REST API to add/index, edit, delete, and search data. Let's go through the process of indexing e-commerce data:</p>
<p>You can use any HTTP client tool to interact with Elasticsearch's REST API. Popular options include cURL, HTTPie, or tools specifically designed for Elasticsearch, like Kibana Dev Tools or Postman. For this task, you will use cURL.</p>
<p>Start by creating an index to hold your e-commerce products. Use the following cURL command to create an index named products:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">-X</span> PUT http://localhost:9200/products</code></pre>
<p>The above command will give you the following output:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><span class="token property">"acknowledged"</span><span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token property">"shards_acknowledged"</span><span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token property">"index"</span><span class="token operator">:</span><span class="token string">"products"</span><span class="token punctuation">}</span></code></pre>
<p>With your index in place, you can start indexing products. For example, let's index a sample product into the products index:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">-X</span> POST <span class="token parameter variable">-H</span> <span class="token string">'Content-Type: application/json'</span> <span class="token parameter variable">-d</span> <span class="token string">'{ "name": "Awesome T-Shirt", "description": "This is an awesome t-shirt for casual wear.", "price": 19.99, "category": "Clothing", "brand": "Example Brand" }'</span> http://localhost:9200/products/_doc</code></pre>
<p>The above command will give you an output like the below when successful:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><span class="token property">"_index"</span><span class="token operator">:</span><span class="token string">"products"</span><span class="token punctuation">,</span><span class="token property">"_id"</span><span class="token operator">:</span><span class="token string">"ZwvjmogB0lKdOCVeL2DZ"</span><span class="token punctuation">,</span><span class="token property">"_version"</span><span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token property">"result"</span><span class="token operator">:</span><span class="token string">"created"</span><span class="token punctuation">,</span><span class="token property">"_shards"</span><span class="token operator">:</span><span class="token punctuation">{</span><span class="token property">"total"</span><span class="token operator">:</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token property">"successful"</span><span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token property">"failed"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token property">"_seq_no"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token property">"_primary_term"</span><span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">}</span></code></pre>
<p>Feel free to experiment with different product attributes and values based on your e-commerce domain.</p>
<p>Congratulations! You have successfully loaded e-commerce data into Elasticsearch. Now let's perform searches to find products.</p>
<h2 id="search-for-a-product-on-elasticsearch" tabindex="-1">Search for a product on Elasticsearch <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#search-for-a-product-on-elasticsearch">#</a></h2>
<p>Elasticsearch provides a comprehensive REST API that allows you to query and retrieve data from your indexes. Let's perform a simple search to find products in the products index:</p>
<p>Search Products: Issue the following command to search for products containing the term "t-shirt" in their name:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">-X</span> GET <span class="token string">"localhost:9200/products/_search?pretty"</span> <span class="token parameter variable">-H</span> <span class="token string">'Content-Type: application/json'</span> -d<span class="token string">' { "query": { "match": { "name": "t-shirt" } } }'</span></code></pre>
<p>Elasticsearch will return the matching products, including the "Awesome T-Shirt" you previously indexed as follows:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"took"</span> <span class="token operator">:</span> <span class="token number">642</span><span class="token punctuation">,</span><br /> <span class="token property">"timed_out"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br /> <span class="token property">"_shards"</span> <span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token property">"total"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br /> <span class="token property">"successful"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br /> <span class="token property">"skipped"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br /> <span class="token property">"failed"</span> <span class="token operator">:</span> <span class="token number">0</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token property">"hits"</span> <span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token property">"total"</span> <span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token property">"value"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br /> <span class="token property">"relation"</span> <span class="token operator">:</span> <span class="token string">"eq"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token property">"max_score"</span> <span class="token operator">:</span> <span class="token number">0.5753642</span><span class="token punctuation">,</span><br /> <span class="token property">"hits"</span> <span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span><br /> <span class="token property">"_index"</span> <span class="token operator">:</span> <span class="token string">"products"</span><span class="token punctuation">,</span><br /> <span class="token property">"_id"</span> <span class="token operator">:</span> <span class="token string">"ZwvjmogB0lKdOCVeL2DZ"</span><span class="token punctuation">,</span><br /> <span class="token property">"_score"</span> <span class="token operator">:</span> <span class="token number">0.5753642</span><span class="token punctuation">,</span><br /> <span class="token property">"_source"</span> <span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"Awesome T-Shirt"</span><span class="token punctuation">,</span><br /> <span class="token property">"description"</span> <span class="token operator">:</span> <span class="token string">"This is an awesome t-shirt for casual wear."</span><span class="token punctuation">,</span><br /> <span class="token property">"price"</span> <span class="token operator">:</span> <span class="token number">19.99</span><span class="token punctuation">,</span><br /> <span class="token property">"category"</span> <span class="token operator">:</span> <span class="token string">"Clothing"</span><span class="token punctuation">,</span><br /> <span class="token property">"brand"</span> <span class="token operator">:</span> <span class="token string">"Example Brand"</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>By following these steps, you've learned how to run Elasticsearch with Docker and Docker Compose, load e-commerce data, and perform searches on it.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/06/elasticsearch-docker/#conclusion">#</a></h2>
<p>In this beginner's guide, you explored the fundamental concepts of Elasticsearch and why it's a valuable tool for e-commerce search and analytics. You also learned about the popularity of Elasticsearch and the big names that use it. You then learned how to set up Elasticsearch using Docker and Docker Compose, which offer convenient ways to manage and deploy your Elasticsearch instance. Additionally, the process of loading sample e-commerce data into Elasticsearch and performing searches to find products was also covered.</p>
<p>Now that you have a solid foundation, you can further explore Elasticsearch's features, such as advanced search queries, filtering, aggregations, and more, to build powerful e-commerce search functionalities. Happy searching and optimizing your e-commerce store!</p>
A beginner's guide to using React Toastify with code examples2023-05-14T12:47:52Zhttps://geshan.com.np/blog/2023/05/react-toastify/<p>React Toastify is the most popular NPM package to show toast messages on a React.js application. In this guide, you will learn how to use React Toastify in a simple React.js app that guesses nationalities for a given name, let’s get going!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-toastify/01react-toastify.jpg" title="Learn how to use React Toasitfy on a React.js app" alt="Learn how to use React Toasitfy on a React.js app" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#why-use-react">Why use React?</a></li>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#options-to-show-messages-in-react">Options to show messages in React</a></li>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#react-toastify">React Toastify</a></li>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#when-to-use-react-toastify">When to use React Toastify</a></li>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#how-to-use-react-toastify">How to use React Toastify</a></li>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#popularity-of-react-toastify">Popularity of React Toastify</a></li>
<li><a href="https://geshan.com.np/blog/2023/05/react-toastify/#conclusion">Conclusion</a></li>
</ul>
<!-- tocstop -->
<h2 id="why-use-react%3F" tabindex="-1">Why use React? <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#why-use-react%3F">#</a></h2>
<p>React is a the most popular JavaScript library for building user interfaces. As per the <a href="https://2022.stateofjs.com/en-US/libraries/front-end-frameworks/">State of JavaScript 2022</a> survey, React is used by 82% of the respondents making it the most used library. Not only that, it has been no. 1 since 2016 in that survey. It is known for its declarative syntax, its component-based architecture, and its ability to be used with a variety of different front-end frameworks.</p>
<p>React is popular for a number of reasons. First, the declarative syntax makes it easy to write code that is both readable and maintainable. Second, React is pretty performant. It is able to render complex user interfaces without sacrificing performance. Third, React is very flexible. It can be used to build a wide variety of different user interfaces, from simple web pages to complex mobile apps.</p>
<p>Eventhough the latest docs React is not favoring <a href="https://create-react-app.dev/">Create React App (CRA)</a>, it is pointing to meta frameworks like Next.js and others. For this guide, we will use a React.js application created with CRA to show the toast messages using React Toasitfy.</p>
<h2 id="options-to-show-messages-in-react" tabindex="-1">Options to show messages in React <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#options-to-show-messages-in-react">#</a></h2>
<p>There are a number of different ways to show messages with React. One option is to use the built-in alert() function. However, this function is not very flexible and it can only be used to show a single message at a time.</p>
<p>Another option is to use a third-party library. The two popular ones on NPM are <a href="https://react-hot-toast.com/">React Hot Toast</a> and <a href="https://fkhadra.github.io/react-toastify/introduction">React Toastify</a>. React Toastify is a library that makes it easy to show toast notifications in React applications or other applicaitons built with meta frameworks that use React in the background like Next.js.</p>
<p>Toast notifications are small, temporary messages that are displayed at the bottom of the screen or some other position on the screen. They are often used to notify users of errors, successes, or other important events. In the next section, you will learn more about React Toastify and how to use it in a React app.</p>
<h2 id="react-toastify" tabindex="-1">React Toastify <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#react-toastify">#</a></h2>
<p>React Toastify is the most popular library used to display toast messages in React applications. It provides a simple and flexible API for creating toast messages that can be customized to fit your application’s look and feel. React Toastify offers different types of toasts, including success, error, warning, and info messages. The library also allows you to set the duration, position, and styling of the toast messages.</p>
<p>React Toastify provides a convenient and customizable way to display toast messages in React applications. Its simplicity, flexibility, and extensive features make it a the most popular choice among developers for handling notifications and user feedback. By using React Toastify, you can enhance the user experience, improve communication, and streamline the presentation of information.</p>
<p>React Toastify offers a powerful and user-friendly solution for displaying toast messages in React applications. It simplifies the process by providing a single component that handles the display of notifications, allowing developers to focus on the content and behavior. React Toastify comes with a range of features, including customizable appearance, position, duration, and the ability to add actions or buttons to the toast. It is compatible with different React versions and actively maintained by the developer community.</p>
<p>React Toastify is a popular library for showing toast notifications in React applications. It is easy to use and it comes with a number of features, such as:</p>
<ul>
<li>Support for different toast types, such as success, error, and warning</li>
<li>Support for different toast positions, such as top, bottom, left, and right</li>
<li>Support for toast animations</li>
<li>Support for toast icons</li>
<li>Support for toast customizability</li>
</ul>
<p>In the next seciton you will learn about when to use a toast message package like React Toastify.</p>
<h2 id="when-to-use-react-toastify" tabindex="-1">When to use React Toastify <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#when-to-use-react-toastify">#</a></h2>
<p>React Toastify is particularly useful in scenarios where you need to display notifications or toast messages to users. Some common use cases include:</p>
<p>Notifications for successful form submissions: After a user submits a form, you can display a success message to provide feedback and acknowledge the completion of the action.</p>
<p>Displaying errors or validation messages: When form validation fails or an error<br />
occurs, React Toastify can be used to show error messages or highlight specific fields that require attention.</p>
<p>Feedback during asynchronous operations: When performing asynchronous operations like API calls or file uploads, you can show loading indicators or progress bars using React Toastify to keep users informed about the ongoing process.</p>
<p>Informational messages: You can use React Toastify to display informative messages or announcements to users, such as system updates, new features, or important notifications.</p>
<p>In the next part, you will learn how to use React Toastify to inform the user about the result of an API call to guess the nationalities for a given name.</p>
<h2 id="how-to-use-react-toastify" tabindex="-1">How to use React Toastify <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#how-to-use-react-toastify">#</a></h2>
<p>React Toastify can be used in any React app be it a native React application or React running behind a meta framework like Next.js or Remix. You can run <a href="https://geshan.com.np/blog/2023/01/nextjs-docker/">Next.js in a docker container</a> too. For this guide, you will implement it in an exiting React.js application that guesses the nationalities of a given name, which is open source and all the code is available on <a href="https://github.com/geshan/name-nationality">GitHub</a>.</p>
<p>Without React Toasitfy the app looks like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-toastify/02react-toastify-without.jpg" title="Name to Nationalities guessing app without using React Toastify" alt="Name to Nationalities guessing app without using React Toastify" />
<p>After adding React Toasitfy to show the success (or error) of fetching the guessed nationalities for a given name the app looks as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-toastify/05react-toastify-app.jpg" title="Name to Nationalities guessing app with React Toastify" alt="Name to Nationalities guessing app with React Toastify" />
<p>To install React Toastify in your React.js applicaiton you should first run:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">--save</span> react-toastify</code></pre>
<p>After that you can import and use the toasitify elements like <code>toast</code> and <code>ToastContainer</code>. You will edit the <code>/src/App.js</code> file as follows, the edited code is highlighted in yellow:</p>
<pre class="language-js"><code class="language-js"><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token keyword">import</span> <span class="token string">'./App.css'</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"><span class="token keyword">import</span> <span class="token punctuation">{</span> Slide<span class="token punctuation">,</span> ToastContainer<span class="token punctuation">,</span> toast <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-toastify'</span><span class="token punctuation">;</span></mark><br /><mark class="highlight-line highlight-line-active"><span class="token keyword">import</span> <span class="token string">'react-toastify/dist/ReactToastify.css'</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>nationalities<span class="token punctuation">,</span> setNationalities<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>personName<span class="token punctuation">,</span> setPersonName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchNationalities</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token keyword">const</span> toastId <span class="token operator">=</span> <span class="token string">'fetched-nationalities'</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token keyword">try</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.nationalize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>personName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> hasCountryData <span class="token operator">=</span> data<span class="token punctuation">.</span>country <span class="token operator">&&</span> data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length</span><br /><span class="highlight-line"> <span class="token keyword">const</span> nationalities <span class="token operator">=</span> hasCountryData <span class="token operator">?</span> data<span class="token punctuation">.</span>country <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token function">setNationalities</span><span class="token punctuation">(</span>nationalities<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> </span><br /><span class="highlight-line"> <span class="token keyword">const</span> message <span class="token operator">=</span> hasCountryData <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> guess(es) found</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">'No nationality match found'</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> toast<span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> <span class="token punctuation">{</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">position</span><span class="token operator">:</span> toast<span class="token punctuation">.</span><span class="token constant">POSITION</span><span class="token punctuation">.</span><span class="token constant">TOP_CENTER</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">autoClose</span><span class="token operator">:</span> <span class="token number">3000</span><span class="token punctuation">,</span> <span class="token comment">//3 seconds</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">hideProgressBar</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">closeOnClick</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">pauseOnHover</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">draggable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> toastId<span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">transition</span><span class="token operator">:</span> Slide</mark><br /><mark class="highlight-line highlight-line-active"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">err: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token punctuation">.</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token function">setNationalities</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> toast<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Cound not fetch nationalities, please try again later'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">position</span><span class="token operator">:</span> toast<span class="token punctuation">.</span><span class="token constant">POSITION</span><span class="token punctuation">.</span><span class="token constant">TOP_RIGHT</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> toastId</mark><br /><mark class="highlight-line highlight-line-active"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span></span><br /><span class="highlight-line"> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">await</span> <span class="token function">fetchNationalities</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token punctuation">(</span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"title-form"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>h2<span class="token operator">></span>Check Name's Nationalities percent<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token string">'20px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>form name<span class="token operator">=</span><span class="token string">"nationalities-form"</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>input</span><br /><span class="highlight-line"> name<span class="token operator">=</span><span class="token string">"personName"</span></span><br /><span class="highlight-line"> type<span class="token operator">=</span><span class="token string">"text"</span></span><br /><span class="highlight-line"> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPersonName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span><br /><span class="highlight-line"> value<span class="token operator">=</span><span class="token punctuation">{</span>personName<span class="token punctuation">}</span></span><br /><span class="highlight-line"> placeholder<span class="token operator">=</span><span class="token string">"Enter a person's name"</span></span><br /><span class="highlight-line"> <span class="token operator">/</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span>Get Nationalities<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"results"</span><span class="token operator">></span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"toast-container"</span><span class="token operator">></span><span class="token operator"><</span>ToastContainer limit<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">2</span><span class="token punctuation">}</span><span class="token operator">/</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></mark><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"nationalities"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">{</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>nationalities<span class="token punctuation">)</span> <span class="token operator">&&</span> nationalities<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span></span><br /><span class="highlight-line"> <span class="token parameter">nationality</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> flagUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://flagcdn.com/w160/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> altText <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nationality<span class="token punctuation">.</span>country_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> flag</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token operator"><</span>div key<span class="token operator">=</span><span class="token punctuation">{</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span>h3<span class="token operator">></span><span class="token punctuation">{</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">(</span>nationality<span class="token punctuation">.</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">%</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>flagUrl<span class="token punctuation">}</span> alt<span class="token operator">=</span><span class="token punctuation">{</span>altText<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token literal-property property">border</span><span class="token operator">:</span> <span class="token string">"1px solid black"</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token punctuation">)</span><span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> </span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></span><br /><span class="highlight-line"></span></code></pre>
<p>Let’s try to understand the changes that have been done to get React Toasitfy working:</p>
<ul>
<li>First you have imported <code>Slide</code>, <code>ToastContainer</code> and <code>toast</code> function from react-toastify and also imported the <code>ReactToastify.css</code> style sheet used to style the toast messages.</li>
<li>After that, on line 11 you have defined the <code>toastId</code> as <code>fetched-nationalites</code> it is used to eliminate duplicates of the same toast later. This will be used later in the code.</li>
<li>In place of setting a message variable, you are calling <code>toast.success</code> on line no. 19. You are also passing other parameters as an object defining the position to show the toast on the top center. You are also specifying other config options like <code>autoClose</code> after 3 seconds, make it draggable, etc. One important config passed is the <code>toastId</code> which prevents duplicates. All these option are well defined in the <a href="https://fkhadra.github.io/react-toastify/positioning-toast">usage section</a> of the React Toasitfy official docs.</li>
<li>Then, you have also defined a <code>toast.error</code> in case there is any error calling the API on line 32. Here as well a couple of configs have been used.</li>
<li>Lastly, you are defining a div with class <code>toast-container</code> that has the <code>ToastContainer</code> element in it. This is the div that houses the toast messages and it has a limit of 2 set on it.</li>
</ul>
<p>If you run the app with <code>npm start</code> and point your browser to <code>http://loccalhost:3000</code> then type <code>chris</code> in the text box you will see an output like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-toastify/03react-toastify-guess-app.gif" title="Name to Nationalities guessing app with React Toastify Running" alt="Name to Nationalities guessing app with React Toastify Running" />
<p>For your reference, all the changes is available as a <a href="https://github.com/geshan/name-nationality/pull/13">pull request</a> on GitHub. You can also try out the app with React Toastify on <a href="https://deploy-preview-13--name-nationality.netlify.app/">Netlify</a>. You can also view the generic React Toastify examples ona Next.js app in this <a href="https://github.com/geshan/react-toastify-examples">GitHub repo</a>. This Next.js example is also running on <a href="https://react-toastify-examples.vercel.app/">Vercel</a>.</p>
<p>This app uses <a href="https://geshan.com.np/blog/2023/02/react-fragments/">React Fragments</a> and if you want you can also add a <a href="https://geshan.com.np/blog/2022/10/react-search-bar/">React Search Bar</a>. In the next section, you will find out that <a href="https://www.npmjs.com/package/react-toastify">React Toastify</a> is the most popular NPM package to show toast messages.</p>
<h2 id="popularity-of-react-toastify" tabindex="-1">Popularity of React Toastify <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#popularity-of-react-toastify">#</a></h2>
<p>Without doubts, React Toastify is the most popular NPM library to show toast message in React. The distant second is React Hot Toast as per <a href="https://npmtrends.com/react-confirm-alert-vs-react-hot-toast-vs-react-toastify-vs-react-toastr-vs-react-toasts">NPM Trends</a> as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-toastify/04react-toastify-popularity.jpg" title="React Toastify is the most popular NPM package to show toast message, second one is Hot React Toast" alt="React Toastify is the most popular NPM package to show toast message, second one is Hot React Toast" />
<p>As you can see, React Toastify has more than 2.5x the number of downloads compared to its nearest competitor <a href="https://react-hot-toast.com/">React Hot Toast</a>. In terms of absolute numbers, React Hot Toast had 565K downloads in the week of 7-May-2023, where as React Toasity has 1.41 million download in the same week. Other libraries like React Confirm Alert, React Toaster and React Toasts don’t come close to the top two libraries to show react toast messages.</p>
<p>If you need to show toast messages in your React.js app React Toasitfy is the safest bet, the second best thing can be React Hot Toast.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/05/react-toastify/#conclusion">#</a></h2>
<p>In this blog post, you explored why React is widely used and the options available for displaying messages in React applications. You learned about React Toastify and provided code examples to demonstrate its usage. Various scenarios where React Toastify can be beneficial, such as form submissions, error handling, asynchronous operations, and informational messages were also discussed.</p>
<p>Remember to leverage the power of React Toastify's configuration options to customize the appearance, position, and behavior of toast messages to align with your application's design and user experience goals.</p>
<p>By incorporating React Toastify into your React projects, you can elevate the way you communicate with users and deliver a more engaging and interactive web application.</p>
<p>Happy coding with React Toastify!</p>
How to use ON DELETE CASCADE in Postgres with an example2023-04-29T12:34:52Zhttps://geshan.com.np/blog/2023/04/delete-cascade-postgres/<p>Postgres is one of the most <a href="https://db-engines.com/en/system/PostgreSQL">popular</a> open-source relational database systems in use today. One of the useful features of PostgreSQL is on delete cascade that simplifies the code in your application. In this guide, you will learn how to set up and use <code>ON DELETE CASCADE</code> in foreign keys in Postgres, let’s get going!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/01delete-cascade-postgres.jpg" title="Learn how to use ON DELETE CASCADE in Postgres" alt="Learn how to use ON DELETE CASCADE in Postgres" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#prerequisites">Prerequisites</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#author-and-quotes-example">Author and Quotes example</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#on-delete-cascade-or-something-else">ON DELETE CASCADE or something else</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#create-tables-on-elephantsql">Create tables on ElephantSQL</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#insert-data-in-created-tables">Insert data in created tables</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#delete-an-author-row">Delete an author row</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#check-the-on-delete-cascade-has-worked">Check the ON DELETE CASCADE has worked</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#conclusion">Conclusion</a></li>
</ul>
<!-- tocstop -->
<h2 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#prerequisites">#</a></h2>
<p>Before diving into the SQL code, below are some prerequisites for this tutorial:</p>
<ol>
<li>You should have a working Postgres server instance to test your code. You can use a local <a href="https://geshan.com.np/blog/2021/12/docker-postgres/">Postgres Docker</a> instance or simply use a free database on <a href="https://www.elephantsql.com/plans.html">Elephant SQL</a> or <a href="https://neon.tech/">Neon.tech</a></li>
<li>Prior experience with any relations database management system (RDBMS) would be helpful.</li>
<li>Previous understanding of how foreign keys work in RDBMS will be advantageous</li>
<li>Being able to read Entity Relationship (ER) diagrams will make it easier for you to understand the context.</li>
</ol>
<p>Given that is mentioned, you can continue with the guide now.</p>
<h2 id="author-and-quotes-example" tabindex="-1">Author and Quotes example <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#author-and-quotes-example">#</a></h2>
<p>For this tutorial, you will use an example of an author and quotes. One author can have multiple quotes and one quote will always have only one author. It can be represented in an ER diagram as follows (diagram generated with <a href="http://dbdiagram.io/">dbdiagram.io</a>):</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/02author-quotes-er.jpg" title="Entity relationship (ER) diagram of Author and Quotes relationship" alt="Entity relationship (ER) diagram of Author and Quotes relationship" />
<p>In terms of Postgres Data Definition Language (DDL), the above ER diagram with two related entities translates to the following create table statements:</p>
<pre class="language-sql"><code class="language-sql"><span class="highlight-line"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> author <span class="token punctuation">(</span></span><br /><span class="highlight-line"> id <span class="token keyword">SERIAL</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span></span><br /><span class="highlight-line"> name <span class="token keyword">character</span> <span class="token keyword">varying</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span></span><br /><span class="highlight-line"> created_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span></span><br /><span class="highlight-line"> updated_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span></span><br /><span class="highlight-line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> quote <span class="token punctuation">(</span></span><br /><span class="highlight-line"> id <span class="token keyword">SERIAL</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span><span class="token punctuation">,</span></span><br /><span class="highlight-line"> quote <span class="token keyword">character</span> <span class="token keyword">varying</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">UNIQUE</span><span class="token punctuation">,</span></span><br /><mark class="highlight-line highlight-line-active"> author_id <span class="token keyword">INTEGER</span> <span class="token keyword">REFERENCES</span> author<span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token keyword">ON</span> <span class="token keyword">DELETE</span> <span class="token keyword">CASCADE</span><span class="token punctuation">,</span></mark><br /><span class="highlight-line"> created_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span></span><br /><span class="highlight-line"> updated_at <span class="token keyword">timestamp</span> <span class="token keyword">with</span> <span class="token keyword">time</span> zone <span class="token keyword">DEFAULT</span> <span class="token keyword">CURRENT_TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span></span><br /><span class="highlight-line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span></code></pre>
<p>There are two entities (tables) <code>author</code> and <code>quote</code>. The author table has 4 columns; id, name, created_at, and udpated_at. <code>ID</code> is a serial which is an integer autoincremented by 1 and the primary key of the table. The <code>name</code> column is a varying character that can be up to 255 characters and cannot be null, it holds the author's name. The <code>created_at</code> and <code>updated_at</code> columns are timestamp columns by default have the current timestamp.</p>
<p>The <code>quote</code> entity (table) also has an integer serial primary key similar to the <code>author</code> table. Then, it has a <code>quote</code> column that can hold up to 255 characters and always needs a value. The interesting column is the foreign key to the <code>author</code> table called <code>author_id</code> as highlighed above.</p>
<p>The <code>auhtor_id</code> foreign key column is an integer and refers to the <code>id</code> column on the author. The main point here is it has <code>ON DELETE CASCADE</code> which means when an author is deleted all the related quotes will also be deleted. This is like a domino effect when the parent row is deleted all its child rows are deleted too.</p>
<p>Depending on how <code>ON DELETE CASCADE</code> is added on relational databases like Postgres, deleting one row on table A can delete related rows on table B, similarly deleting one row on table B can delete related rows on table C. This creates a ripple effect that can delete many related children and children of children rows. So you have to be careful about how to set up on delete cascade.</p>
<p>After the <code>author_id</code> column, the <code>quote</code> table has <code>created_at</code> and <code>updated_at</code> similar to the columns with the same name on the <code>author</code> table.</p>
<h3 id="on-delete-cascade-or-something-else" tabindex="-1">ON DELETE CASCADE or something else <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#on-delete-cascade-or-something-else">#</a></h3>
<p>To delete the related child rows for a parent row, there are mainly two ways. The first is to let the database server delete the related child rows with <code>ON DELETE CASCADE</code>. The second is not deleting the child rows from the database server with RESTRICT or NO ACTION. You can read more about it on the <a href="https://www.postgresql.org/docs/current/ddl-constraints.html#:~:text=Restricting%20and%20cascading%20deletes%20are,you%20do%20not%20specify%20anything.">official docs</a> of Postgres.</p>
<p>If you choose to not delete the rows on the database server level, you will have to delete all the child rows manually from your application before the parent row(s) can be deleted. Like most things in tech, there are tradeoffs for both approaches. You should understand the implications of using the ripple/domino effect on the database level or manually deleting the child rows from the application so that the parent row can be deleted without any errors.</p>
<p>When you create records with relationships you must create the parent first then the child and its child. In case of delete, you have to delete the leaf (last level children), the branches (children) and then only delete the parent (root). It can be understood with a diagram better:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/03create-delete.jpg" title="How to create and delete records in a one to many parent child relationship" alt="How to create and delete records in a one to many parent child relationship" />
<p>Depending on how much data there is on the database and which database engine (if any) the database server uses, sometimes it might be wiser to not have strict foreign keys. If you want to add a column to a table with a million rows that have a child table with billion rows, things would get complicated quite quickly when the foreign keys are strict and could block both the tables while running the <code>ALTER TABLE</code> script.</p>
<p>In the next section, you will see how to create the above tables and insert some data. Then delete one parent row and see that its child rows are automatically deleted due to the ON DELETE CASCADE instruction on the foreign key.</p>
<h3 id="create-tables-on-elephantsql" tabindex="-1">Create tables on ElephantSQL <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#create-tables-on-elephantsql">#</a></h3>
<p>For this example, you will use ElephantSQL, you can follow their <a href="https://www.elephantsql.com/docs/index.html">documentation</a> to create an empty database for free. Create a new free database named something like <code>quotes-author-01</code> and go to the “Browser” section and run the above create table statements using the blue "Execute" button as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/04create-tables.jpg" title="Create tables author and quote with in a one to many parent child relationship" alt="reate tables author and quote with in a one to many parent child relationship" />
<p>The above SQL statements will create two tables author and quotes. The main point to focus on here is the <code>author_id INTEGER REFERENCES author(id) ON DELETE CASCADE,</code> which sets up the ON DELETE CASCADE mechanism. So, whenever any author row is deleted, any related quote rows will also be deleted. Let’s see how that happens in the next section.</p>
<h3 id="insert-data-in-created-tables" tabindex="-1">Insert data in created tables <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#insert-data-in-created-tables">#</a></h3>
<p>To delete data you will need to add some data to the two tables. To add data in the <code>author</code> and <code>quote</code> table created in the previous section, please run the following on the same “Browser” screen on ElephantSQL (you can run them on your local Postgres instance too).</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> author<span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <br /><span class="token punctuation">(</span><span class="token string">'Martin Fowler'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token string">'Bjarne Stroustrup'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">(</span><span class="token string">'John Johnson'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <br /> <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> quote <span class="token punctuation">(</span>quote<span class="token punctuation">,</span> author_id<span class="token punctuation">)</span> <span class="token keyword">VALUES</span><br /> <span class="token punctuation">(</span><span class="token string">'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'If you have to spend effort looking at a fragment of code and figuring out what it is doing, then you should extract it into a function and name the function after the "what".'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'There are only two kinds of languages: the ones people complain about and the ones nobody uses.'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'If you think it is simple, then you have misunderstood the problem.'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token punctuation">(</span><span class="token string">'First, solve the problem. Then, write the code.'</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>It will look like the below when the insert statements are executed successfully:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/05insert-data.jpg" title="Insert data on tables author and quote" alt="Insert data on tables author and quote" />
<p>To make sure that the insert statements have worked correctly, you can run the following SELECT statement and see all the relevant data joining both the author and quote table:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> q<span class="token punctuation">.</span>id<span class="token punctuation">,</span> q<span class="token punctuation">.</span>quote<span class="token punctuation">,</span> a<span class="token punctuation">.</span>name<span class="token punctuation">,</span> a<span class="token punctuation">.</span>id <span class="token keyword">as</span> author_id<span class="token punctuation">,</span> q<span class="token punctuation">.</span>created_at <br /><span class="token keyword">FROM</span> quote q <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> author a <span class="token keyword">on</span> a<span class="token punctuation">.</span>id <span class="token operator">=</span> q<span class="token punctuation">.</span>author_id<span class="token punctuation">;</span></code></pre>
<p>It is a simple inner join between the <code>author</code> and <code>quote</code> table using the <code>author_id</code> foreign key. The output of the above SELECT statement will look as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/06select-data-before-delete.jpg" title="Select data before ON CASCADE DELETE with 5 rows" alt="Select data before ON CASCADE DELETE with 5 rows" />
<p>Now given the test data is inserted into both tables, In the next section, you will delete an author row and see that it deletes the related quote rows as well.</p>
<h3 id="delete-an-author-row" tabindex="-1">Delete an author row <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#delete-an-author-row">#</a></h3>
<p>Now, it is time to test the <code>ON DELETE CASCADE</code> in action. To verify that the cascade deleting works as expected and will delete the quotes related to the author you will delete the author with id 2 which is Bjarne Stourstrup. This DELETE statement will delete one row in the <code>author</code> table and also delete 2 more rows in the <code>quote</code> table. It will happen because you have set up the <code>ON DELETE CASCADE</code> on the foreign key from the <code>quote</code> table to the <code>author</code> table. To delete the row with id 2 on the author, you can run the following statement on the “Browser” screen on ElephantSQL:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">DELETE</span> <span class="token keyword">from</span> author <span class="token keyword">WHERE</span> id <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token comment"># Bjarne Stroustrup</span></code></pre>
<p>When it executes without errors, it will look as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/07on-delete-cascade.jpg" title="Delete author with id 2" alt="Delete author with id 2" />
<p>You have successfully deleted row id 2 on the author, the row for Bjarne Stroustrup. Now it should have deleted the two quotes by Bjarne which is described in the next section.</p>
<h3 id="check-the-on-delete-cascade-has-worked" tabindex="-1">Check the ON DELETE CASCADE has worked <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#check-the-on-delete-cascade-has-worked">#</a></h3>
<p>The author Bjarne Stroustrup with id 2 had two quotes on the quote table with ids 3 and 4. To check that both the related quotes are deleted when the author is deleted you can again run the following select statement that joins those two tables:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> q<span class="token punctuation">.</span>id<span class="token punctuation">,</span> q<span class="token punctuation">.</span>quote<span class="token punctuation">,</span> a<span class="token punctuation">.</span>name<span class="token punctuation">,</span> a<span class="token punctuation">.</span>id <span class="token keyword">as</span> author_id<span class="token punctuation">,</span> q<span class="token punctuation">.</span>created_at <br /><span class="token keyword">FROM</span> quote q <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> author a <span class="token keyword">on</span> a<span class="token punctuation">.</span>id <span class="token operator">=</span> q<span class="token punctuation">.</span>author_id<span class="token punctuation">;</span></code></pre>
<p>After deleting the author with id 2 (Bjarne Stroustrup) due to the ON DELETE CASCADE in place it would delete the two quotes too as seen in the output below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/delete-cascade-postgres/08after-delete.jpg" title="After ON DELETE CASCADE related quotes of the author id 2 is deleted too" alt="After ON DELETE CASCADE related quotes of the author id 2 is deleted too" />
<p>Congrats! Now you understand how the domino effect of ON DELETE CASCADE works in Postgres. It is a similar concept in other relational database systems like MySQL.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/04/delete-cascade-postgres/#conclusion">#</a></h2>
<p>In this tutorial, you learned how to set up an ON DELETE CASCADE with a foreign key in Postgres using the example of one Author having multiple Quotes schema. After that, you added some example data and then deleted an author to see the effect of ON DELETE CASCADE. In effect, it deleted the related quotes for the deleted author from the database server level without adding any more application-level code.</p>
<p>I hope you learned how ON DELETE CASCADE works on Postgres, it is a similar approach in other relations databases too.</p>
How to use class names NPM package to add multiple class names to a React.js component2023-04-17T12:24:52Zhttps://geshan.com.np/blog/2023/04/npm-classnames/<p>React.js is undoubtedly one of the <a href="https://geshan.com.np/blog/2022/10/react-search-bar/#popularity-of-react">most popular</a> front-end libraries. There are multiple ways to add multiple class names to a div in a React Component, using class names NPM package makes it very easy. In this post, you will learn how to use <a href="https://www.npmjs.com/package/classnames">class names NPM package</a> in a React.js application. Let’s get going!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/npm-classnames/01npm-classnames.jpg" title="Learn how to add multiple class names to a React.js component using Class names NPM package" alt="Learn how to add multiple class names to a React.js component using Class names NPM package" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#prerequisites">Prerequisites</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#example-app---name-to-nationalities-guesser">Example app - Name to Nationalities guesser</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#get-the-app-running-locally">Get the app running locally</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#task-on-hand---conditionally-add-a-css-class">Task on hand - conditionally add a CSS class</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#add-classes-with-simple-string-concat">Add classes with simple string concat</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#add-classes-with-classnames">Add classes with Classnames</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#install-classnames">Install classnames</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#use-class-names">Use class names</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/04/npm-classnames/#conclusion">Conclusion</a></li>
</ul>
<h2 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#prerequisites">#</a></h2>
<p>Before you get your hands dirty with the code, below are some requisites:</p>
<ul>
<li>Prior experience with Git and GitHub will be necessary</li>
<li>Any prior knowledge of React will be helpful</li>
<li>A general understanding of how APIs work and are called from React.js would be needed.</li>
</ul>
<p>Given those are mentioned, now you can learn about the example app that will be used in this guide, the app will guess the nationalities of a provided name as discussed next.</p>
<h2 id="example-app---name-to-nationalities-guesser" tabindex="-1">Example app - Name to Nationalities guesser <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#example-app---name-to-nationalities-guesser">#</a></h2>
<p>For the scope of this blog post, you will use an open-source app built with React.js. It is a simple yet useful app that will take in a name and guess the nationalities for that name by calling the <a href="http://nationalize.io/">Nationalize.io</a> API. It will then render the guessed percentages with flags of the country calling another Flag Image API.</p>
<p>You can see the app in action below for the name <code>chris</code>:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/npm-classnames/02name-nationalities.jpg" title="Name to nationalities guessing App working without NPM classnames" alt="Name to nationalities guessing App working without NPM classnames" />
<p>The app’s code is open source on <a href="https://github.com/geshan/name-nationality">GitHub</a> and you can see the app running without class names on <a href="https://deploy-preview-9--name-nationality.netlify.app/">Netlify</a>. Notice that there are not styles on the text <code>5 guess(es) found</code>.</p>
<h3 id="get-the-app-running-locally" tabindex="-1">Get the app running locally <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#get-the-app-running-locally">#</a></h3>
<p>To run the app locally, you can clone the repository with the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone <span class="token parameter variable">-b</span> before-classnames git@github.com:geshan/name-nationality.git</code></pre>
<p>After that you can install the needed NPM dependencies by running <code>npm install</code>, then you can run the app with <code>npm start</code>. It will show up on the browser like below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/npm-classnames/03name-nationaliities-app.jpg" title="Name to nationalities guessing App working locally" alt="Name to nationalities guessing App working locally" />
<p>Great! Your Name guessing app is running you can play around with it.</p>
<h2 id="task-on-hand---conditionally-add-a-css-class" tabindex="-1">Task on hand - conditionally add a CSS class <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#task-on-hand---conditionally-add-a-css-class">#</a></h2>
<p>Now you can look at the code by opening the project in the IDE of your choice. The app calls the <a href="https://nationalize.io/">Nationalize API</a>. As it is a third-party service so it can be down or too slow. Like any other HTTP request, there is no guarantee that it will work all the time. This is already handled in the code, in case of an error a message <code>Could not fetch nationalities, try again later.</code> is shown. The task is to add a <code>success</code> or <code>error</code> class to the div with the class <code>message</code> in the <code>App.js</code> main component.</p>
<p>For this, you can add the following CSS styles in the <code>App.css</code> files for the <code>success</code> and the <code>error</code> classes as follows:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.error</span> <span class="token punctuation">{</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> #842029<span class="token punctuation">;</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> #f8d7da<span class="token punctuation">;</span><br /> <span class="token property">border-color</span><span class="token punctuation">:</span> #f5c2c7<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.success</span> <span class="token punctuation">{</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> #0f5132<span class="token punctuation">;</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> #d1e7dd<span class="token punctuation">;</span><br /> <span class="token property">border-color</span><span class="token punctuation">:</span> #badbcc<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The CSS code is self-explanatory, if the <code>error</code> class is added, it will show a pink background and maroon text. For the success case, it displays a light green background with dark green text. In the next section, you will add the success and error class to the div that shows the message with simple string concatenation.</p>
<h2 id="add-classes-with-simple-string-concat" tabindex="-1">Add classes with simple string concat <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#add-classes-with-simple-string-concat">#</a></h2>
<p>The task is straightforward if the API call is successful the div with the <code>message</code> class will have a <code>success</code> class appended to it, in case of any error the <code>error</code> class will be added after the <code>message</code> class.</p>
<p>This work can be done in multiple ways, one of those is to do it with a variable that will have an initial value of the string <code>message</code>. If the HTTP call to Nationalize API is successful you will append <code> success</code> to the variable. In case of an error is encountered while calling the API you will append <code> error</code> to the variable. This can be seen in the code below:</p>
<pre class="language-js"><code class="language-js"><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token keyword">import</span> <span class="token string">'./App.css'</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>nationalities<span class="token punctuation">,</span> setNationalities<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>personName<span class="token punctuation">,</span> setPersonName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token keyword">const</span> <span class="token punctuation">[</span>messageClassNames<span class="token punctuation">,</span> setMessageClassNames<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchNationalities</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token keyword">let</span> msgClassNames <span class="token operator">=</span> <span class="token string">'message'</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token keyword">try</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.nationalize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>personName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> hasCountryData <span class="token operator">=</span> data<span class="token punctuation">.</span>country <span class="token operator">&&</span> data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length</span><br /><span class="highlight-line"> <span class="token keyword">const</span> nationalities <span class="token operator">=</span> hasCountryData <span class="token operator">?</span> data<span class="token punctuation">.</span>country <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token function">setNationalities</span><span class="token punctuation">(</span>nationalities<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> </span><br /><span class="highlight-line"> <span class="token keyword">const</span> message <span class="token operator">=</span> hasCountryData <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> guess(es) found</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">'No nationality match found'</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> msgClassNames <span class="token operator">+=</span> <span class="token string">' success'</span><span class="token punctuation">;</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token function">setMessageClassNames</span><span class="token punctuation">(</span>msgClassNames<span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token function">setMessage</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">err: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token punctuation">.</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token function">setNationalities</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> msgClassNames <span class="token operator">+=</span> <span class="token string">' error'</span><span class="token punctuation">;</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token function">setMessageClassNames</span><span class="token punctuation">(</span>msgClassNames<span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token function">setMessage</span><span class="token punctuation">(</span><span class="token string">'Could not fetch nationalities, try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span></span><br /><span class="highlight-line"> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">await</span> <span class="token function">fetchNationalities</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token punctuation">(</span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"title-form"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>h2<span class="token operator">></span>Check Name's Nationalities percent<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token string">'20px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>form name<span class="token operator">=</span><span class="token string">"nationalities-form"</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>input</span><br /><span class="highlight-line"> name<span class="token operator">=</span><span class="token string">"personName"</span></span><br /><span class="highlight-line"> type<span class="token operator">=</span><span class="token string">"text"</span></span><br /><span class="highlight-line"> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPersonName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span><br /><span class="highlight-line"> value<span class="token operator">=</span><span class="token punctuation">{</span>personName<span class="token punctuation">}</span></span><br /><span class="highlight-line"> placeholder<span class="token operator">=</span><span class="token string">"Enter a person's name"</span></span><br /><span class="highlight-line"> <span class="token operator">/</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span>Get Nationalities<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"results"</span><span class="token operator">></span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span>messageClassNames<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>message<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></mark><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"nationalities"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">{</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>nationalities<span class="token punctuation">)</span> <span class="token operator">&&</span> nationalities<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span></span><br /><span class="highlight-line"> <span class="token parameter">nationality</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> flagUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://flagcdn.com/w160/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> altText <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nationality<span class="token punctuation">.</span>country_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> flag</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token operator"><</span>div key<span class="token operator">=</span><span class="token punctuation">{</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span>h3<span class="token operator">></span><span class="token punctuation">{</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">(</span>nationality<span class="token punctuation">.</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">%</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>flagUrl<span class="token punctuation">}</span> alt<span class="token operator">=</span><span class="token punctuation">{</span>altText<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token literal-property property">border</span><span class="token operator">:</span> <span class="token string">"1px solid black"</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token punctuation">)</span><span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> </span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></span><br /><span class="highlight-line"></span></code></pre>
<p>The above <code>App.js</code> is a modified version of the <a href="https://github.com/geshan/name-nationality/blob/before-classnames/src/App.js">same file before</a> adding the logic to include the <code>success</code> and <code>error</code> classes to the div with the <code>message</code> class. The main changes in this version as highlighted above in yellow are:</p>
<ul>
<li>A state variable named <code>messageClassNames</code> is initialized on line 8 with an empty string.</li>
<li>On line no. 11, another variable named <code>msgClassNames</code> is initialized with the string <code>message</code>.</li>
<li>Later on 19-20, as the API call is successful the string <code> success</code> is added to the <code>msgClassNames</code> and the value for <code>messageClassNames</code> is updated with the value of <code>msgClassNames</code>. The variable <code>msgClassNames</code> at this stage has the <code> success</code> appended to it.</li>
<li>In case of error, on lines 25-26, the <code>msgClassNames</code> variable has <code> error</code> appended to it and is set to the <code>messageClassNames</code> state variable.</li>
<li>The final change is on line 55, where the <code>message</code> string has been replaced with the <code>{messageClassNames}</code> which has the dynamic class names depending on the result of the API call.</li>
</ul>
<p>After this change, if you test the Name to nationalities guessing app with <code>chirs</code> it will look like the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/npm-classnames/04npm-classnames-success.jpg" title="Name to nationalities guessing App in success mode" alt="Name to nationalities guessing App in success mode" />
<p>Notice that the <code>5 guess(es) found</code> text has the styling of the success class applied to it. To test the error scenario, on Chrome you can in the “dev tool” go to the “Network” tab and choose “Offline” and then try the request again it will fail. It will show an output like the one below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/npm-classnames/05npm-classnames-error.jpg" title="Name to nationalities guessing App in error mode" alt="Name to nationalities guessing App in error mode" />
<p>You have seen an imperative way to add the <code>success</code> or <code>error</code> depending on the API’s response. Let’s suppose you had to add 3 more classes then managing the if/else logic will be overly complicated. This is where the glorified string concatenator NPM package <code>classnames</code> comes to save the day, as discussed next.</p>
<h2 id="add-classes-with-classnames" tabindex="-1">Add classes with Classnames <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#add-classes-with-classnames">#</a></h2>
<p>As you have seen above, imperatively adding multiple class names in React with string concatenation is not easy. The code is convoluted and prone to errors if there are more than 2 classes to be added to the same HTML element. The solution to this issue is the Classnames NPM package.</p>
<p>Meet <a href="https://github.com/JedWatson/classnames">Classnames</a>, A simple JavaScript utility for conditionally joining classNames together. If you term it a “smart” string concatenator you will not be wrong. Interestingly, the official <a href="https://react.dev/reference/react-dom/components/common#applying-css-styles">React docs</a> also mentions <code>classnames</code> in the “How to apply multiple CSS classes conditionally” section. In the next part, you will find out how to install the <code>classnames</code> package.</p>
<h3 id="install-classnames" tabindex="-1">Install classnames <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#install-classnames">#</a></h3>
<p>To install the <code>classnames</code> package with NPM you can execute:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> –save classnames</code></pre>
<p>This will add the <code>classnames</code> NPM package to your React.js project. You can use it to dynamically and declaratively add multiple classes to the HTML elements of your React.js components.</p>
<p>Again, the task is simple, if the call to <a href="http://nationalize.io/">Nationalize.io</a> API is fine add the <code>success</code> class. In case of any error add the <code>error</code> class to the <code>div</code> that already has the <code>message</code> class. You will see the code to do so, now using <code>classnames</code> in the next section.</p>
<h3 id="use-class-names" tabindex="-1">Use class names <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#use-class-names">#</a></h3>
<p>The code below uses <code>classnames</code> (without other features like dedupe) to accomplish the above-mentioned task:</p>
<pre class="language-js"><code class="language-js"><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token keyword">import</span> <span class="token string">'./App.css'</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"><span class="token keyword">import</span> classNames <span class="token keyword">from</span> <span class="token string">'classnames'</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>nationalities<span class="token punctuation">,</span> setNationalities<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>personName<span class="token punctuation">,</span> setPersonName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token punctuation">[</span>messageClassNames<span class="token punctuation">,</span> setMessageClassNames<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchNationalities</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token keyword">let</span> errorInFetch <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token keyword">try</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.nationalize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>personName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> hasCountryData <span class="token operator">=</span> data<span class="token punctuation">.</span>country <span class="token operator">&&</span> data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length</span><br /><span class="highlight-line"> <span class="token keyword">const</span> nationalities <span class="token operator">=</span> hasCountryData <span class="token operator">?</span> data<span class="token punctuation">.</span>country <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token function">setNationalities</span><span class="token punctuation">(</span>nationalities<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> </span><br /><span class="highlight-line"> <span class="token keyword">const</span> message <span class="token operator">=</span> hasCountryData <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>country<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> guess(es) found</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">'No nationality match found'</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token function">setMessage</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">err: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token punctuation">.</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> errorInFetch <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token function">setNationalities</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token function">setMessage</span><span class="token punctuation">(</span><span class="token string">'Could not fetch nationalities, try again later.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><mark class="highlight-line highlight-line-active"></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token keyword">const</span> msgClassNames <span class="token operator">=</span> <span class="token function">classNames</span><span class="token punctuation">(</span><span class="token punctuation">{</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string-property property">'success'</span><span class="token operator">:</span> <span class="token operator">!</span>errorInFetch<span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string-property property">'error'</span><span class="token operator">:</span> errorInFetch<span class="token punctuation">,</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token function">setMessageClassNames</span><span class="token punctuation">(</span>msgClassNames<span class="token punctuation">)</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span></span><br /><span class="highlight-line"> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">await</span> <span class="token function">fetchNationalities</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token punctuation">(</span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>header className<span class="token operator">=</span><span class="token string">"App-header"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"title-form"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>h2<span class="token operator">></span>Check Name's Nationalities percent<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">marginBottom</span><span class="token operator">:</span> <span class="token string">'20px'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>form name<span class="token operator">=</span><span class="token string">"nationalities-form"</span> onSubmit<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>input</span><br /><span class="highlight-line"> name<span class="token operator">=</span><span class="token string">"personName"</span></span><br /><span class="highlight-line"> type<span class="token operator">=</span><span class="token string">"text"</span></span><br /><span class="highlight-line"> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setPersonName</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span><br /><span class="highlight-line"> value<span class="token operator">=</span><span class="token punctuation">{</span>personName<span class="token punctuation">}</span></span><br /><span class="highlight-line"> placeholder<span class="token operator">=</span><span class="token string">"Enter a person's name"</span></span><br /><span class="highlight-line"> <span class="token operator">/</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span>Get Nationalities<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"results"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span>messageClassNames<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>message<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"nationalities"</span><span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">{</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>nationalities<span class="token punctuation">)</span> <span class="token operator">&&</span> nationalities<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span></span><br /><span class="highlight-line"> <span class="token parameter">nationality</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> flagUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://flagcdn.com/w160/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.jpg</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> altText <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nationality<span class="token punctuation">.</span>country_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> flag</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token operator"><</span>div key<span class="token operator">=</span><span class="token punctuation">{</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span>h3<span class="token operator">></span><span class="token punctuation">{</span>nationality<span class="token punctuation">.</span>country_id<span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token punctuation">{</span><span class="token punctuation">(</span>nationality<span class="token punctuation">.</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">%</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>flagUrl<span class="token punctuation">}</span> alt<span class="token operator">=</span><span class="token punctuation">{</span>altText<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token literal-property property">border</span><span class="token operator">:</span> <span class="token string">"1px solid black"</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token punctuation">)</span><span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> </span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></span><br /><span class="highlight-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span></span><br /><span class="highlight-line"></span></code></pre>
<p>As seen above, the main code changes have been again highlighted in yellow. These changes are as follows:</p>
<ul>
<li>The <code>classnames</code> function is imported from the <code>classnames</code> package on line no. 3</li>
<li>On line 12, a new variable called <code>errorInFetch</code> is introduced and initialized with the value <code>false</code>.</li>
<li>After that, at line 23 in the catch section, the <code>errorInFetch</code> variable is set to true. So in case of the happy case of no errors from the API call to <a href="http://nationalize.io/">Nationalize.io</a>, this variable will still stay <code>false</code>.</li>
<li>Then, in lines 28-32 the main usage can be seen, where the <code>classnames</code> function is called with an object which instructs to always add the class name <code>message</code> but adding either <code>success</code> or <code>error</code> classname depends on the value of the <code>errorInFetch</code> variable.</li>
<li>As the <code>messageClassNames</code> is already used for the class name of the div showing message it will pick up the new dynamic class names automatically.</li>
</ul>
<p>For your reference, you can also view the above changes as a <a href="https://github.com/geshan/name-nationality/pull/12">pull request</a>. Running the code will give the same output as above when done imperatively with string concatenation. A better and easier way to show sucess/error messages with better UI can be with <a href="https://geshan.com.np/blog/2023/05/react-toastify/">React Toastify</a>, without the need to meddle with the class names.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/04/npm-classnames/#conclusion">#</a></h2>
<p>In this tutorial, you learned how to add multiple class names to an HTML element of a React.js component in two ways. The first way is a manual process that concatenates strings. This way is difficult as well as prone to error because it is imperative. The second way you learned to add multiple classes was by using the <code>classnames</code> NPM package. The second way was an easy, one-shot solution in a declarative approach. The second way is clear, concise, and less prone to errors.</p>
<p>I hope this guide has helped you easily add many class names to HTML elements of your React.js components.</p>
A comprehensive guide to Serverless Containers includes 3 services to run them2023-04-11T12:47:52Zhttps://geshan.com.np/blog/2023/04/serverless-containers/<p>Serverless containers are one of the easiest and most useful ways to run your applications in the cloud with minimal effort. On top of being simple and quick to get started, serverless containers are affordable and you can use any language/framework. In this post, you will learn about serverless containers (not serverless vs containers) and the 3 services that run them, let’s get started!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/serverless-container/01serverless-containers.jpg" title="Learn about Serverless Containers with this comprehensive guide" alt="Learn about Serverless Containers with this comprehensive guide" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#what-is-serverless%3F">What is serverless?</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#faas-is-one-aspect-of-serverless">FaaS is one aspect of serverless</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#containers%2C-what-are-they%3F">Containers, what are they?</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#serverless-containers">Serverless Containers</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#the-sweet-spot">The sweet spot</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#components-for-running-serverless-containers">Components for running serverless containers</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#services-offering-serverless-containers">Services offering serverless containers</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#google-cloud-run">Google Cloud Run</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#aws-fargate">AWS Fargate</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#azure-container-instance">Azure Container Instance</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#quick-comparison-of-the-big-3">Quick comparison of the Big 3</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#advantages-of-using-serverless-containers">Advantages of using serverless containers</a></li>
<li><a href="https://geshan.com.np/blog/2023/04/serverless-containers/#conclusion">Conclusion</a></li>
</ul>
<h2 id="what-is-serverless%3F" tabindex="-1">What is serverless? <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#what-is-serverless%3F">#</a></h2>
<p>Before diving into serverless containers, let’s understand what serverless means in general. Serverless computing or simply serverless means different things to different people. As per <a href="https://www.cloudflare.com/en-gb/learning/serverless/what-is-serverless/">Cloudflare</a>, serverless computing is:</p>
<blockquote>
<p>Serverless computing is a method of providing backend services on an as-used basis. Servers are still used, but a company that gets backend services from a serverless vendor is charged based on usage, not a fixed amount of bandwidth or number of servers.</p>
</blockquote>
<p>So it is clear that in the serverless model, the provider takes care of the server management and capacity planning. As the consumer, you use it as a pay-per-use. This equates to two things, first one is, the developers can focus on writing and deploying code without worrying about underlying infrastructure and scaling it. The second and most important one is the cost is linear to the usage, which means if you use the compute power/bandwidth once you pay 1 cent for instance if it is used 100K times you pay 1K dollars.</p>
<p>With this concept, many services are working the <a href="https://aws.amazon.com/serverless/">serverless model</a> like Amazon S3, Amazon DynamoDB, Amazon API Gateway, etc. You pay as much as you used it. In the case of a database like DynamoDB on-demand capacity, it is not provisioned when not used so you pay almost nothing, when there are read/write operations then you pay as per the number of reads or write operations. This is a good thing and a bad thing depending on how you look at it. Then in addition to these “serverless” backends as a service there is the infamous Function as a Service (FaaS) which is improperly synonymous with serverless as discussed next.</p>
<h3 id="faas-is-one-aspect-of-serverless" tabindex="-1">FaaS is one aspect of serverless <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#faas-is-one-aspect-of-serverless">#</a></h3>
<p>Now with the knowledge of what serverless is, you will be more enlightened to understand that Function as a Service (FaaS) is only one aspect of the whole serverless spectrum. But it is “improperly” used as a synonym for serverless. With FaaS, developers write small, single-purpose functions that are executed in response to events. The cloud provider handles all the infrastructure required to run the functions, including scaling, and availability, The events can be an HTTP trigger, a file uploaded to storage like an S3 bucket, a message added to a queue, etc. While FaaS is a powerful tool, it does have some limitations. It's not suitable for all types of applications and can be expensive for long-running tasks.</p>
<p>The most popular FaaS services offered by the big 3 cloud providers are <a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html">Lambda</a> by AWS, <a href="https://azure.microsoft.com/en-au/products/functions">Azure Functions</a> by Microsoft Azure and <a href="https://cloud.google.com/functions">Cloud Functions</a> by Google Cloud Platform (GCP). Below is a quick comparison of all 3 FaaS offerings by the big 3 Cloud providers:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/serverless-container/02serverless-containers-faas.jpg" title="Quick comparision of FaaS offerings by the big 3 clouds AWS, Azure and GCP" alt="Quick comparision of FaaS offerings by the big 3 clouds AWS, Azure and GCP" />
<p>All of them are charged by pay per invocation model. The drawback of Function as a Service (FaaS) is that all the infrastructure is brought up and torn down for each request which causes the <a href="https://dashbird.io/blog/can-we-solve-serverless-cold-starts">cold start</a> problem. The main takeaway here is Serverless > Functions as a Service (FaaS). In the next section, you will learn about containers.</p>
<h2 id="containers%2C-what-are-they%3F" tabindex="-1">Containers, what are they? <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#containers%2C-what-are-they%3F">#</a></h2>
<p>It is safe to say that containers were made mainstream by Docker. It was Docker who successfully democratized a technology that was already used by big companies like Google years back. As per <a href="https://www.docker.com/resources/what-container/">Docker</a>:</p>
<blockquote>
<p>A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.</p>
</blockquote>
<p>Thereby it is a <a href="https://opencontainers.org/">standard</a> and you as a software engineer ship the whole stack (your code, its dependencies, the language runtime as well as the Operating System) when you ship changes. <a href="https://www.docker.com/">Docker</a> is the most popular container technology but there are other players like <a href="https://www.redhat.com/en/topics/containers/what-is-rkt">Rocket (rkt)</a> too which is not that popular.</p>
<p>Containers are a lightweight way of packaging software that allows applications to run reliably in different computing environments. Containers isolate applications from the underlying system, providing consistent runtime environments across different computing environments, including development, testing, and production.</p>
<blockquote>
<p>Containers also make it easy to package and deploy applications, allowing developers to build, ship, and run applications anywhere.</p>
</blockquote>
<p>Containers work by virtualizing the operating system, allowing multiple containers to run on a single host system without interfering with each other. Each container has its own file system, networking, and computing resources. This makes it easy to run multiple applications on the same host system, without the need for separate virtual machines. As they are very lightweight and fast you can potentially run hundreds (if not thousands) of containers on a host machine.</p>
<p>In the case of Docker, the package made with the underlying operating system, language runtime, and code (both third-party and your custom code) following a recipe called Dockerfile turns into a static image (also called Docker Image). When these images are run they are called Docker Containers. It can be seen visually below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/serverless-container/03docker-build-run.jpg" title="Visual representation of Docker build to image and run as container" alt="Visual representation of Docker build to image and run as container" />
<p>Containers help your application become cloud provider agnostic (with the use of things like Kubernetes) and it helps with the <a href="https://geshan.com.np/blog/2018/10/why-use-docker-3-reasons-from-a-development-perspective/">development side</a> too. It is safe to say <a href="https://geshan.com.np/blog/2018/11/4-ways-docker-changed-the-way-software-engineers-work-in-past-half-decade/">Docker and containers have changed the way we software engineers work</a>. They provide a level of abstraction between the application and the infrastructure, making it easy to move an application between different environments without having to worry about dependencies or configuration. In the next part, you will learn about serverless containers.</p>
<h2 id="serverless-containers" tabindex="-1">Serverless Containers <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#serverless-containers">#</a></h2>
<p>Amazon says <a href="https://aws.amazon.com/blogs/apn/serverless-containers-are-the-future-of-container-infrastructure/">Serverless Containers are the Future of Container Infrastructure</a>, so let’s understand what they are. As per <a href="https://www.aquasec.com/cloud-native-academy/serverless-architecture-platforms-benefits-best-practices/serverless-containers/">Cloud Native wiki</a> by Aqua, Serverless containers means:</p>
<blockquote>
<p>The term “serverless containers” refers to technologies that enable cloud users to run containers, but outsource the effort of managing the actual servers or computing infrastructure they are running on.</p>
</blockquote>
<p>Running containers at scale in production is not easy. That is where tools like <a href="https://kubernetes.io/">Kubernetes</a> come into play. Google’s Kubernetes won the container orchestration war some years back after battling with the likes of Docker Swarm and Apache Mesos. Running and scaling a Kubernetes cluster is not only difficult but requires a different set of skill sets. As a software engineer without a platform or DevOps/SRE team, it might be wiser to not run Kubernetes on Production on your own. This is where Serverless containers shine as you don’t have to provision or manage the infrastructure needed to run, operate and scale the containers.</p>
<p>Serverless containers combine the benefits of serverless computing with the flexibility of containerization.</p>
<blockquote>
<p>With serverless containers, developers can deploy containerized applications without worrying about the underlying infrastructure.</p>
</blockquote>
<p>This means that developers can focus on writing code, while the cloud provider handles the infrastructure management, including the server, operating system, and container management.</p>
<p>If your application gets 100s or even 1000s of requests per second the cloud provider running the containers on its serverless containers platform will scale up the number of containers to a higher number as per the upper limit selected by you. There are configurations to set the right amount of resources (CPU and memory) you can set per running container.</p>
<blockquote>
<p>There is no fine-grained control of the resource metrics like 80% CPU usage or 70% memory consumption to scale the containers up or down that is usually managed by the cloud service provider for you.</p>
</blockquote>
<p>Serverless containers also provide a more cost-effective solution for running containerized applications than traditional container deployment models. Because they are billed on the invocation basis you pay for the time your application uses the resources which can be 0 if the application doesn’t get any traffic. And 0 containers = 0 costs as it is serverless and pay per use. But if you were to run a Kubernetes cluster there will be a minimum cost for the nodes that have to be up 24/7 even if the is no traffic.</p>
<blockquote>
<p>In addition to that, you are not bound to a set list of runtime environments like Python, Javascript, and others. If you want to run Rust, R, or even Pascal it is possible with containers and thereby possible with serverless containers too.</p>
</blockquote>
<p>In the next section, you will know about the sweet spot serverless containers hit.</p>
<h3 id="the-sweet-spot" tabindex="-1">The sweet spot <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#the-sweet-spot">#</a></h3>
<p>Software engineering teams started to move away from real hardware racked in the server room to multiple virtual machines put into the same hardware. This gave them full control as they could SSH into the machine as the root user and install or change anything they needed. On the other side of this cloud spectrum is serverless Functions (FaaS) where the software engineer only writes code and deploys it as a serverless function. The engineer has no control over the execution model, resources, and how the function scales when it gets many requests. Faas provides a very high level of ease and abstraction with a focus on the code for software engineers.</p>
<p>Besides containers on that spectrum lies containers that give a bit less control than VMs but also provide a good degree of ease and abstraction. Similarly, Platform as a Service (Paas) sits on the other side of the spectrum with higher ease and abstraction and lower control.</p>
<p>The sweet spot for both control and ease comes with serverless containers.</p>
<blockquote>
<p>With serverless containers, the software engineer can still have control of the operating system, the language runtime and its versions, etc as the application is containerized.</p>
</blockquote>
<p>Along with that control, the engineer doesn’t need to worry about scaling and resources to a degree with serverless containers giving it the needed points for ease and abstraction too. You can understand this comparison and the spectrum visually as follows:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/serverless-container/04serverless-containers-sweet-spot.jpg" title="Serverless containers sweet spot of both control and ease" alt="Serverless containers sweet spot of both control and ease" />
<p>With modern serverless container services like Google <a href="https://geshan.com.np/blog/2019/11/why-use-google-cloud-run-5-compelling-reasons/">Cloud run</a> you can also run long-running tasks like a cron job with <a href="https://cloud.google.com/run/docs/create-jobs">Cloud Run Jobs</a>. In the next section, you will learn about the components needed for running serverless containers.</p>
<h2 id="components-for-running-serverless-containers" tabindex="-1">Components for running serverless containers <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#components-for-running-serverless-containers">#</a></h2>
<p>To run containers in a production environment you will need some components to work together. First of all, you will need your application to be containerized (read Dockerized) with a Dockerfile that defines the steps to create the container image. Next, similar to GitHub you will need a container registry to push the container image too. The container registry can be public like <a href="https://hub.docker.com/">Docker Hub</a>’s public version or a private one like <a href="https://cloud.google.com/container-registry">Google container registry</a> or <a href="https://aws.amazon.com/ecr/">AWS Elastic Container Registry</a>.</p>
<p>When the application is deployed, the deploying command will pull the image from the registry and run it. This is where you can run your container images in <a href="https://kubernetes.io/">Kubernetes</a> as <a href="https://kubernetes.io/docs/concepts/workloads/pods/">pods</a> within services. Kubernetes is the layer and orchestrator that takes care of scaling your containers/pods depending on the auto-scaling configuration provided.</p>
<p>The other way to run your images as containers without the need to spin up a full Kubernetes cluster is to host them in one of the serverless container services. You can see the full flow in the image below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/serverless-container/05docker-run.jpg" title="Visual representation of Docker build to image push to registry, pull and run on a platform" alt="Visual representation of Docker build to image push to registry, pull and run on a platform" />
<p>This leads us to the services providing serverless container hosting from the big three cloud providers that are discussed next.</p>
<h2 id="services-offering-serverless-containers" tabindex="-1">Services offering serverless containers <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#services-offering-serverless-containers">#</a></h2>
<p>Many cloud providers are offering serverless container platforms. These platforms allow developers to deploy containerized applications without worrying about the underlying infrastructure, and benefit from the scalability and cost-effectiveness of serverless computing. For this post, the concern is mostly on the big three clouds AWS, Microsoft Azure, and Google Cloud Platform.</p>
<h3 id="google-cloud-run" tabindex="-1">Google Cloud Run <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#google-cloud-run">#</a></h3>
<p>In my experience, <a href="https://cloud.google.com/run">Cloud Run</a> service inside the Google Cloud Platform is the best serverless containers platform with unbeatable developer experience. You can deploy a containerized or a <a href="https://cloud.google.com/docs/buildpacks/build-application">build pack-supported application</a> with a click of a <a href="https://cloud.google.com/blog/products/serverless/introducing-cloud-run-button-click-to-deploy-your-git-repos-to-google-cloud">button</a>. Google Cloud platform defines Cloud Run as:</p>
<blockquote>
<p>Cloud Run is a managed compute platform that lets you run containers directly on top of Google's scalable infrastructure.</p>
</blockquote>
<p>Google Cloud Run is serverless so it abstracts away all infrastructure management. You can focus on what matters most, building great applications. With Cloud Run, you can deploy containers to handle incoming requests, because it is serverless you only pay for the exact duration of requests.</p>
<p>In addition to that you can specify the number of maximum containers, your application should scale up to in case of a higher load. Similarly, you can also specify the number of minimum containers, which can be 0 making it serverless and pay-per-use. You can read about more <a href="https://geshan.com.np/blog/2019/11/why-use-google-cloud-run-5-compelling-reasons/">reasons to use Google Cloud Run</a> for your applications.</p>
<p>If Cloud Run can handle the scale of <a href="https://www.gcppodcast.com/post/episode-236-ikea-retail-ingka-group-with-matt-lawson/">Ikea</a> and <a href="https://cloud.google.com/blog/products/serverless/a-developers-guide-to-new-features-in-cloud-run">Mail Chimp</a>, it can surely handle your workloads. You can also read up on <a href="https://geshan.com.np/blog/2019/11/from-0-to-working-serverless-url-for-a-containerized-app-with-google-cloud-run-slides-and-video/">how to get a working URL with Google Cloud Run</a> in a matter of minutes. Amongst other great <a href="https://cloud.google.com/run#all-features">features</a>, Google Cloud Run also provides <a href="https://cloud.google.com/run/docs/mapping-custom-domains">custom domain names</a> with HTTPs and <a href="https://cloud.google.com/run/docs/rollouts-rollbacks-traffic-migration">gradual rollouts with percent traffic</a> out of the box.</p>
<p>You can view some of the amazing features in this FireShip <a href="https://youtube.com/watch?v=3OP-q55hOU">video</a>. Google Cloud Run is <a href="https://cloud.google.com/blog/products/serverless/knative-based-cloud-run-services-are-ga">based</a> on <a href="https://knative.dev/docs/">Knative</a>. Knative is an open source solution to run serverless containers. In the next section, you will learn about AWS Fargate.</p>
<h3 id="aws-fargate" tabindex="-1">AWS Fargate <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#aws-fargate">#</a></h3>
<p>It will not be an overstatement to mention that Amazon AWS and its services are complicated. Among the hundreds of AWS services, <a href="https://aws.amazon.com/fargate/">AWS Fargate</a> also lets you run containers in a serverless way, as per AWS:</p>
<blockquote>
<p>AWS Fargate is a serverless, pay-as-you-go compute engine that lets you focus on building applications without managing servers. AWS Fargate is compatible with both Amazon Elastic Container Service (ECS) and Amazon Elastic Kubernetes Service (EKS).</p>
</blockquote>
<p>So, AWS Fargate is a serverless compute engine for containers that allows you to run containers without having to manage servers or clusters. With Fargate, you can deploy Docker containers to AWS with ease. Fargate also offers automatic scaling, ensuring that your applications are always available and performing optimally.</p>
<p>The main website states that Farget is useful for Web apps, APIs, and Microservices. It can run and scale containers, and also supports AI and ML training applications. But, the main issue here is the mention of ECS and EKS. If those details of the infrastructure are surfaced then it defeats the whole purpose of being able to run containers in a serverless fashion without needing to dabble with infrastructure.</p>
<p>After watching this <a href="https://www.youtube.com/watch?v=WsvuIxaCQGg">video</a> about Fargate, it does show up the Cluster, VPC, and details of EC2, security group, and other things. There is a segregation of cluster, service, and task. At this point, it is not as easy to use as Google Cloud run which is classic AWS. In the next part, you will know about Azure Container Instances (ACI)</p>
<h3 id="azure-container-instance" tabindex="-1">Azure Container Instance <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#azure-container-instance">#</a></h3>
<p>Azure Container Instances is a fully managed serverless container solution that allows you to easily run containers without managing servers or clusters. With <a href="https://azure.microsoft.com/en-us/products/container-instances/">Azure Container Instances</a>, you can deploy containers quickly and easily, without the need for infrastructure management. The official docs term ACI as:</p>
<blockquote>
<p>Azure Container Instances is a solution for any scenario that can operate in isolated containers, without orchestration.</p>
</blockquote>
<p>As per this <a href="https://youtube.com/watch?v=7G_oDLON7Us">video</a> by Microsoft the Azure Container Instances (ACI) demo has a full-on YAML file to define the container. To be honest, the configuration does not look easy to set up.</p>
<p>One of the key benefits of Azure Container Instances is its simplicity. You can deploy containers with just a few clicks, using the Azure portal, Azure CLI, or Azure Resource Manager templates. This makes it easy to get started with container deployment, even if you have limited experience with serverless computing. Scaling is the main issue with Azure container instances. As per the official <a href="https://learn.microsoft.com/en-us/azure/container-instances/container-instances-overview">documentation</a>: “For scenarios where you need full container orchestration, including service discovery across multiple containers, automatic scaling, and coordinated application upgrades, we recommend Azure Kubernetes Service (AKS).” This translates to, ACI does not scale your containers it is more like a <a href="https://geshan.com.np/blog/2022/05/docker-commands/#docker-run">Docker Run</a> command on the cloud, for scaling containers use AKS.</p>
<p>With all of this, it is up to you to choose the right service to host your serverless containers on a Container as a Service (CasS) platform. There are other services too like <a href="https://cloud.yandex.com/en/services/serverless-containers">Yandex serverless containers</a> and Alibaba’s <a href="https://www.alibabacloud.com/product/elastic-container-instance">Elastic Container Instances</a> but these type of services cannot be tagged as battle tested. In the next section, you will know about a video that compares the above three offerings.</p>
<h2 id="quick-comparison-of-the-big-3" tabindex="-1">Quick comparison of the Big 3 <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#quick-comparison-of-the-big-3">#</a></h2>
<p>This <a href="https://youtube.com/watch?v=Jq8MY1ZGjno">video</a> with a comparison of Google Cloud Run, AWS Fargate, and Azure Container Instances (ACI) is a great one. Keep in mind it is from Aug 2020, so things should have changed in the past 3 years. The video is below:</p>
<div style="position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%; margin-bottom: 1rem;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/Jq8MY1ZGjno" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;" allowfullscreen=""></iframe>
</div>
<p>It would be recommended that you do not miss the <a href="https://youtube.com/watch?v=Jq8MY1ZGjno?t=742">summary</a>, <a href="https://youtube.com/watch?v=Jq8MY1ZGjno?t=790">recap</a> and <a href="https://youtube.com/watch?v=Jq8MY1ZGjno?t=910">comparison</a>.</p>
<blockquote>
<p>He concludes that Google Cloud Run is the best to host serverless containers.</p>
</blockquote>
<p>As it can scale to 0 and up easily and you don’t need to manage any underlying infrastructure at all. In the next section, you will learn about the advantages of using serverless containers.</p>
<h2 id="advantages-of-using-serverless-containers" tabindex="-1">Advantages of using serverless containers <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#advantages-of-using-serverless-containers">#</a></h2>
<p>Below are some advantages of using serverless containers in general and with Google Cloud Run:</p>
<ul>
<li>There is no need to learn and new paradigm or framework. As long as your application can be containerized and stateless (as serverless containers don’t keep state) it can be run as serverless containers. Also, you are not constrained by the limited runtimes provided by FaaS.</li>
<li>The infrastructure and scaling are generally abstracted away from you. You need to set the resources correctly and specify the minimum and the maximum number of containers you need for your application depending on the volume of requests. So, you also get automatic scaling for free.</li>
<li>You get a custom domain name and HTTPs URL out of the box in case you are using Google Cloud Run. You also get gradual rollouts with Cloud Run.</li>
<li>Depending on the Cloud provider, serverless containers play well with the other great services provided by the cloud provider. For instance, Google Cloud run works well with <a href="https://cloud.google.com/build">Cloud Build</a> and you can push your container easily to <a href="https://cloud.google.com/container-registry">Google Container Registry</a>. You also get logs out of the box with <a href="https://cloud.google.com/logging">Google Cloud logging</a> for your containers with 0 configs needed.</li>
<li>If your application/service has less traffic, with scaling to 0 the cost of running serverless containers is minimal. Especially with Google Cloud Run’s amazing <a href="https://cloud.google.com/run/pricing">pricing</a> you get “2 million requests free per month” which means you can run your hobby projects for $0 a month.</li>
</ul>
<p>As you are using containers, they are portable. If you want to move to a full-fledged Kubernetes cluster later that can be done easily. The lock-in is less with containers in general.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/04/serverless-containers/#conclusion">#</a></h2>
<p>In conclusion, serverless containers offer a powerful and flexible way to build and deploy applications in the cloud. By combining the benefits of containers with the ease of use and low operational overhead of serverless computing, developers can focus on building great applications without worrying about the underlying infrastructure. You also learned about the components of running containers in general and serverless containers.</p>
<blockquote>
<p>With several cloud providers offering serverless container platforms, including Google Cloud Run, AWS Fargate, and Azure Container Instance, it's easier than ever to get started with serverless containers and unlock their many benefits.</p>
</blockquote>
<p>Even with the serverless container services Google Cloud Run shines among the big 3 cloud offerings. It is simple, easy to use, abstracts the underlying infrastructure, and scales containers easily to 0.</p>
<blockquote>
<p>If you want to dabble with serverless containers Google Cloud Run is your best option.</p>
</blockquote>
<p>Keep exploring! Don’t walk, Cloud Run to serverless containers.</p>
How to run MongoDB with Docker and Docker Compose a Step-by-Step guide2023-03-29T12:37:52Zhttps://geshan.com.np/blog/2023/03/mongodb-docker-compose/<p>MongoDB is an open-source document database that is designed to scale and provide high availability. In this guide, you will learn how to run MongoDB with Docker and Docker Compose. Let's get going!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/01mongodb-docker-docker-compose.jpg" title="Learn how to use MongoDB with Docker and Docker Compose" alt="Learn how to use MongoDB with Docker and Docker Compose" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#what-is-mongodb">What is MongoDB?</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#why-use-mongodb">Why use MongoDB?</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#prerequisites">Prerequisites</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#run-mongodb-with-docker">Run MongoDB with Docker</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#run-mongodb-with-docker-compose">Run MongoDB with docker-compose</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#running-mongodb-using-docker-compose-with-a-node.js-app">Running MongoDB using docker-compose with a Node.js app</a></li>
</ul>
<h2 id="what-is-mongodb%3F" tabindex="-1">What is MongoDB? <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#what-is-mongodb%3F">#</a></h2>
<p><a href="https://www.mongodb.com/">MongoDB</a> is a NoSQL database that stores data in flexible, JSON-like documents. It is designed to scale horizontally across many commodity servers, providing high availability with automatic failover and data redundancy. MongoDB's query language is expressive and powerful, allowing developers to work with data naturally as you can store and retrieve JSON easily.</p>
<p>It has a community edition and an enterprise edition too. MongoDB also has a cloud offering called MongoDB <a href="https://www.mongodb.com/atlas">Atlas</a>.</p>
<h2 id="why-use-mongodb%3F" tabindex="-1">Why use MongoDB? <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#why-use-mongodb%3F">#</a></h2>
<p>MongoDB is a popular choice for modern applications due to its flexibility and scalability. It can store structured and unstructured data, making it a good fit for applications with changing or unpredictable data requirements. Its <a href="https://www.mongodb.com/document-databases">document-based</a> data model makes it easy to work with JSON data, which is widely used in web applications.</p>
<p>Additionally, MongoDB is designed to <a href="https://www.mongodb.com/databases/scaling">scale horizontally</a>, allowing it to handle large amounts of data and traffic. With its flexible data model and easy-to-use interface, it has become a popular choice for modern applications.</p>
<h2 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#prerequisites">#</a></h2>
<p>To move further and dive deeper into the code, you will need the following:</p>
<ul>
<li>Any prior experience running or working with MongoDB will be helpful.</li>
<li>You should have Docker and Docker compose running on the machine you want to execute the example app</li>
<li>Previous experience working with Node.js and NPM CLI will be beneficial but not required.</li>
<li>Knowing how to use Git and GitHub will be useful</li>
</ul>
<p>Please keep in mind that the examples are run on a Mac and will run on a *nix system. No guarantees are made that the commands below will run fine on a Windows machine. Now it is time to move with the commands.</p>
<h2 id="run-mongodb-with-docker" tabindex="-1">Run MongoDB with Docker <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#run-mongodb-with-docker">#</a></h2>
<p>For all the examples below, you are going to use the MongoDB 6-jammy docker tag which is version 6 of Mongo on the Ubuntu Jammy OS. To Run MongoDB 6 with docker you can execute the <a href="https://geshan.com.np/blog/2022/05/docker-commands/#docker-run">Docker run</a> command which will pull the docker image if not locally available and run it. The command is given below:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> run <span class="token parameter variable">--rm</span> <span class="token parameter variable">--name</span> mongo6-jammy <span class="token parameter variable">-e</span> <span class="token assign-left variable">MONGO_INITDB_ROOT_USERNAME</span><span class="token operator">=</span>admin <span class="token parameter variable">-e</span> <span class="token assign-left variable">MONGO_INITDB_ROOT_PASSWORD</span><span class="token operator">=</span>VRuAd2Nvmp4ELHh5 <span class="token parameter variable">-e</span> <span class="token assign-left variable">MONGO_INITDB_DATABASE</span><span class="token operator">=</span>test <span class="token parameter variable">-v</span> /tmp/mongo-data:/data/db mongo:6-jammy</code></pre>
<p>You have run the Docker run command with the <code>--rm</code> flag which will remove the container after it stops. The added –name<code>parameters add a name to the running container which you can see from the [docker ps](https://geshan.com.np/blog/2022/05/docker-commands/#docker-ps) command. After naming the container</code>mongo6-jammy<code>you pass in 3 environment variables with the</code>-e<code>parameters. Those are</code>MONGO_INITDB_ROOT_USERNAME<code>, </code>MONGO_INITDB_ROOT_PASSWORD<code>, and </code>MONGO_INITDB_DATABASE<code>to specify the root username, password, and the database name respectively. After that you add the</code>-v<code>to include the volume in the running container, in the above example the local</code>/tmp/mongo-data<code>is mapped to</code>/data/db<code>on the container. This is done to keep the data intact when the container restarts. Note here that as you are using</code>/tmp` when the machine restarts data will be lost.</p>
<p>After the container is running with the name <code>mongo6-jammy</code> and waiting for connections as seen in the mange below.</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/02mongodb-running-with-docker.jpg" title="CLI output of MongoDB runnign with Docker" alt="CLI output of MongoDB runnign with Docker" />
<p>You can execute other commands inside the running container. For now, you will execute the mongo shell, then insert a document, and retrieve it. First, you will run the mongo shell (mongosh) by executing the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> mongo6-jammy mongosh <span class="token parameter variable">-u</span> admin <span class="token parameter variable">-p</span> VRuAd2Nvmp4ELHh5 <span class="token parameter variable">--authenticationDatabase</span> admin</code></pre>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/03mongodb-shell.jpg" title="MongoDB shell for MongoDB running with Docker" alt="MongoDB shell for MongoDB running with Docker" />
<p>The MongoDB server is running and you have access to it with the mongo shell from inside the container. Now to insert a document by running the following commands in the Mongo shell:</p>
<pre class="language-bash"><code class="language-bash">db.tutorial.insertOne<span class="token punctuation">(</span><span class="token punctuation">{</span>title: <span class="token string">"test tutorial"</span>, description: <span class="token string">"description for test tutorial"</span>, published: false, createdAt: <span class="token string">"2023-03-30T12:04:15.008Z"</span>, updatedAt: <span class="token string">"2023-03-30T12:04:15.008Z"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The above command will insert a tutorial titled “test tutorial” and also have other attributes as seen above. When the command completes successfully it will give an output as below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/04mongodb-insert-one.jpg" title="MongoDB shell Insert one Tutorial output" alt="MongoDB shell Insert one Tutorial output" />
<p>As you have inserted a document in the <code>tutorial</code> database. Now to find the inserted document you can run:</p>
<pre class="language-bash"><code class="language-bash">db.tutorial.find<span class="token punctuation">(</span><span class="token punctuation">{</span>title: <span class="token string">"test tutorial"</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>That will result in the following where it finds the inserted document in the database</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/05mongodb-find.jpg" title="MongoDB shell Find Tutorial output" alt="MongoDB shell Find Tutorial output" />
<p>Hurray! You were able to run MongoDB with Docker and insert and view the inserted document. You also found out that running Mongo just using the Docker run command has multiple parameters you need to get right and it is not easy to remember all of those. This is where the power of making the process of running MongoDB declarative comes in. In the next section, you will learn how to run MongoDB with docker-compose.</p>
<h2 id="run-mongodb-with-docker-compose" tabindex="-1">Run MongoDB with docker-compose <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#run-mongodb-with-docker-compose">#</a></h2>
<p>As you have seen running MongoDB with a regular Docker command is not an easy task and you need to remember all the parameters. A much easier and comparatively more declarative way is to use a docker-compose file like the one below:</p>
<pre class="language-bash"><code class="language-bash">version: <span class="token string">'3.8'</span><br />services:<br /> mongodb:<br /> image: mongo:6-jammy<br /> ports:<br /> - <span class="token string">'27017:27017'</span><br /> volumes:<br /> - dbdata6:/data/db<br />volumes:<br /> dbdata6:</code></pre>
<p>It is a simple docker-compose file that uses the official MongoDB image with the tag <code>6-jammy</code>. It runs it as <code>mongodb</code> and uses a docker-managed volume so that the data for the database is kept intact even if the container restarts. Here you also map the port <code>27012</code> to the host’s port <code>27017</code>.</p>
<p>You can run the MongoDB server with <code>docker-compose -f docker-compose-mongo-only.yml up</code> given you save the above file as <code>docker-compose-mongo-only.yml</code>. To execute the Mongo shell on the container that is run with docker-compose you can run <code>docker-compose exec mongodb mongosh</code> and then run the above commands to see how it works. In the next section, you will learn how to run MongoDB with docker-compose which is accessed by another Node.js application.</p>
<h2 id="running-mongodb-using-docker-compose-with-a-node.js-app" tabindex="-1">Running MongoDB using docker-compose with a Node.js app <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#running-mongodb-using-docker-compose-with-a-node.js-app">#</a></h2>
<p>For the next example, you will run MongoDB with Docker compose. MongoDB will be accessible to an example application built with Node.js and Express. This example application is an API to do CRUD operations for Tutorials. The code for this API is open source on <a href="https://github.com/bezkoder/node-express-mongodb">GitHub</a> and you can follow this <a href="https://www.bezkoder.com/node-express-mongodb-crud-rest-api/">tutorial</a> to know how this demo REST API app is built.</p>
<p>You will dockerize the Node.js part of the application with the following dockerfile at the root of the project:</p>
<pre class="language-bash"><code class="language-bash">FROM node:18-alpine<br /><br />WORKDIR /src<br />COPY package.json package-lock.json /src/<br />RUN <span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">--production</span><br /><br />COPY <span class="token builtin class-name">.</span> /src<br /><br />EXPOSE <span class="token number">8085</span><br /><br />CMD <span class="token punctuation">[</span><span class="token string">"node"</span>, <span class="token string">"server.js"</span><span class="token punctuation">]</span><br /></code></pre>
<p>You can learn more about how to use <a href="https://geshan.com.np/blog/2020/11/nodejs-with-docker/">Node.js with Docker</a> to understand the concept better. Next, you will add a <code>docker-compose.yml</code> file at the root of the project to link up the Node.js container with the MongoDB container that will look as follows:</p>
<pre class="language-bash"><code class="language-bash">version: <span class="token string">'3.8'</span><br /><br />services:<br /> node-app:<br /> build: <span class="token builtin class-name">.</span><br /> image: node-app<br /> environment:<br /> - <span class="token assign-left variable">MONGODB_URL</span><span class="token operator">=</span>mongodb://mongodb:27017/node-boilerplate<br /> ports:<br /> - <span class="token string">'8085:8085'</span><br /> depends_on:<br /> - mongodb<br /> volumes:<br /> - .:/src<br /> networks:<br /> - node-network<br /><br /> mongodb:<br /> image: mongo:6-jammy<br /> ports:<br /> - <span class="token string">'27017:27017'</span><br /> volumes:<br /> - dbdata6:/data/db<br /> networks:<br /> - node-network<br /><br />volumes:<br /> dbdata6:<br /><br />networks:<br /> node-network:<br /> driver: bridge</code></pre>
<p>Let’s have a look at the contents of this docker-compose file:</p>
<ul>
<li>First, you specify the version of docker-compose as <code>3.8</code></li>
<li>After that you define two <code>services</code> which are <code>node-app</code> and <code>mongodb</code></li>
<li>For the <code>node-app</code> container you build it with <code>.</code> which will take the above Dockerfile to build the image and run it. You also add the <code>MONGODB_URL</code> environment variable which points to the MongoDB container defined later in the same file.</li>
<li>Then you map the ports of the application from the Docker container port of <code>8085</code> to the host port of <code>8085</code> as the Node.js Express application runs on that port.</li>
<li>Consequently you define that the <code>node-app</code> container depends on the <code>mongodb</code> container, there are better ways to make the dependency blocking but this is a basic way.</li>
<li>After that, you map the local folder <code>./</code> to the <code>./src</code> inside the container as a volume so that changes made from the host reflect in the container file system.</li>
<li>Then link up the app with the <code>node-network</code>, this is how the two containers of the app and the MongoDB database can communicate with each other as they belong to the same network.</li>
<li>Subsequently you define the mongodb service similar to the above docker-compose file, the only extra thing here is the inclusion of the network. The volumes are the same as the above docker-compose file.</li>
<li>Finally the network called <code>node-network</code> is defined as a <code>bridge</code> driver between the containers in the network.</li>
</ul>
<p>All the code for this app and the dockerzing process is available in this <a href="https://github.com/geshan/node-express-mongodb">GitHub</a> repository, for your reference. Now, you can run the app and MongoDB in tandem with:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">docker-compose</span> up</code></pre>
<p>You will see the following output where the MongoDB has started successfully and the app has connected to MongoDB too:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/06mongodb-docker-compose.jpg" title="MongoDB running with Docker compose and Node.js app connecting to it" alt="MongoDB running with Docker compose and Node.js app connecting to it" />
<p>To add a tutorial you can run the following cURL command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">--location</span> <span class="token parameter variable">--request</span> POST <span class="token string">'http://localhost:8085/api/tutorials'</span> <span class="token parameter variable">--header</span> <span class="token string">'Content-Type: application/json'</span> --data-raw <span class="token string">'{ "title": "How to run MongoDB with docker and docker-compose; a step-by-step guide", "description": "You must read this post :)"}'</span></code></pre>
<p>If ran successfully it will give an output like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/07mongodb-insert-curl.jpg" title="MongoDB and Node.js app - insert Tutorail with a cURL command" alt="MongoDB and Node.js app - insert Tutorail with a cURL command" />
<p>Now you can open the browser of your choice and hit <code>http://localhost:8085/api/tutorials</code> and you can see the following output:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/mongodb-docker-compose/08mongodb-nodejs-app-output.jpg" title="MongoDB and Node.js app - browser outupt to list tutorials" alt="MongoDB and Node.js app - browser outupt to list tutorials" />
<p>Congratulations! You have now successfully connected MongoDB running with Docker compose to a Node.js Express API that can show and manage tutorials.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/03/mongodb-docker-compose/#conclusion">#</a></h2>
<p>In this post, you first learned about what is MongoDB and why to use it. Then you learned how to run Mongo DB with Docker run commands. Then you upped the complexity a bit by running the same <code>6-jammy</code> version of MongoDB with Docker compose. Then towards the end, you could connect and Node.js Express app with MongoDB all using Docker Compose.</p>
<p>I hope you learned how to run MongoDB with Docker and Docker Compose, kudos!</p>
A step-by-step guide to using Inquirer.js for creating a CLI app in Node.js2023-03-25T12:27:57Zhttps://geshan.com.np/blog/2023/03/inquirer-js/<p>Inquirer.js is a useful NPM package to create Command Line Interface (CLI) apps with Node.js. You can make interactive interfaces by using Inquirer with questions of type option, list, checkbox, input, etc. This makes the CLI application built in Node.js with Inquirer.js useful. In this guide, you will learn how to create a basic CLI app in Node.js with Inquirer.js, let’s get started!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/inquirer-js/01inquirer-js.jpg" title="Learn how to use Inquirer.js to bulid CLI apps in Node.js" alt="Learn how to use Inquirer.js to bulid CLI apps in Node.js" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#example-app">Example App</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#prerequisites">Prerequisites</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#initial-setup">Initial setup</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#install-inquirer.js-and-axios">Install inquirer.js and Axios</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#code-to-get-the-first-name">Code to get the first name</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#code-to-guess-gender-and-nationality-calling-apis">Code to guess gender and nationality calling APIs</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#sew-up-everything-together">Sew up everything together</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#popularity-of-inquirer.js">Popularity of Inquirer.js</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#inquirer.js-plugins">Inquirer.js plugins</a></li>
<li><a href="https://geshan.com.np/blog/2023/03/inquirer-js/#conclusion">Conclusion</a></li>
</ul>
<h2 id="example-app" tabindex="-1">Example App <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#example-app">#</a></h2>
<p>For this tutorial, you will create a command line application that will ask for a first name and then try to determine the nationality and gender of that name by calling a couple of APIs. Both gender and nationalities will have a probability provided by respective APIs and the app will look like the below when complete:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/inquirer-js/02inquirer-js-app-demo.gif" title="Running CLI app built with Inquirer.js in Node.js" alt="Running CLI app built with Inquirer.js in Node.js" />
<p>This is not a simple listing of the options avaiable in Inquirer.js. So get ready to build a simple yet complete and useful CLI app using Inquirer.js.</p>
<h3 id="prerequisites" tabindex="-1">Prerequisites <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#prerequisites">#</a></h3>
<p>Before we dive in, below are some prerequisites for better understanding the code:</p>
<ol>
<li>Knowledge of how to use Node.js and install NPM packages is required</li>
<li>General understanding of how promises and async/await work is necessary</li>
<li>Prior experience using Git and GitHub will be helpful</li>
<li>Any prior knowledge of building CLI apps will be beneficial</li>
</ol>
<p>Now you can get your hands dirty with some commands and code.</p>
<h3 id="initial-setup" tabindex="-1">Initial setup <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#initial-setup">#</a></h3>
<p>To get the basic setup of the project with a readme and the git ignore file you can clone the repository with the following command:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone <span class="token parameter variable">-b</span> initial-setup git@github.com:geshan/inquirer-demo.git</code></pre>
<p>Then you can go into this folder with the basic setup with <code>cd inquirer-demo</code>. To set up the project as a Node.js NPM project you will have to run:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init <span class="token parameter variable">-y</span></code></pre>
<p>The above command will initialize the project as an NPM project and the <code>-y</code> flag accepts the command with all the default values. At this point, you will have a <code>package.json</code> file at the root of the project. One important thing here is to add the <code>” type”: “module”,</code> as seen <a href="https://github.com/geshan/inquirer-demo/blob/master/package.json#L6">here</a> in your package.json file to allow the usage of <code>import</code> in place of <code>require</code> in the scripts. In the next section, you will install the needed NPM packages.</p>
<h3 id="install-inquirer.js-and-axios" tabindex="-1">Install inquirer.js and Axios <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#install-inquirer.js-and-axios">#</a></h3>
<p>To build your basic but useful command line interface application with Node.js, you will install two packages. Those two NPM packages are <a href="https://github.com/SBoudrias/Inquirer.js">Inquirer.js</a> and Axios. You will use Inquirer to get the input from the user over the CLI. Axios will be used to do GET requests to the API that guess the gender and nationalities of the given first name.</p>
<p>To install both packages you can execute:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">--save</span> inquirer axios</code></pre>
<p>This will install both packages and add them to the package.json file too. Next, you will code up the part to get the first name and ask for which actions to perform.</p>
<h3 id="code-to-get-the-first-name" tabindex="-1">Code to get the first name <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#code-to-get-the-first-name">#</a></h3>
<p>Now as you have the necessary package installed and available for use, the next part is to write code to get the first name and operations the user wants to perform. To do this using Inquirer.js with validation you will write the code as seen below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> inquirer <span class="token keyword">from</span> <span class="token string">'inquirer'</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> answers <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getAnswers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'The answers are: '</span><span class="token punctuation">,</span> answers<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">There was an error while talking to the API: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token punctuation">.</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">getAnswers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> inquirer<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'firstName'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What is your first name?'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'input'</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">validate</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>firstName<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Please provide a first name'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">if</span><span class="token punctuation">(</span>firstName<span class="token punctuation">.</span>length <span class="token operator"><=</span> <span class="token number">3</span> <span class="token operator">||</span> firstName<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Please provide a first name between 4 and 20 characters long'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> firstName<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'options'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What would you like to guess for the given first name?'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'checkbox'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">choices</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'gender'</span><span class="token punctuation">,</span> <span class="token string">'nationality'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">validate</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>options<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Choose at least one of the above, use space to choose the option'</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>You can see here, the inquirer package is imported to ask for input from the user. Then you have defined an async <a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIFE</a> to enable async/await syntax. In this guide I wrote for another publication, you can learn all about <a href="https://blog.appsignal.com/2022/11/09/how-to-handle-async-code-in-javascript.html">async JavaScript</a> including callbacks, promises and async/await syntax.</p>
<p>In this IIFE, the <code>getAnswers</code> function is called with the <code>await</code> keyword as it returns a promise that resolves to the <code>answers</code> object. Then the <code>answers</code> object is logged to see what is captured from the user. In case of an error, the error is logged on the console with a <code>console.error</code>.</p>
<p>The main part of this file is in the <code>getAnswers</code> function. It starts by returning the result of an <code>inquirer.prompt</code> that returns a <a href="https://github.com/SBoudrias/Inquirer.js/#inquirerpromptquestions-answers---promise">promise</a>. With the <code>prompt</code> method you can pass an array of questions and get back the answers object with the answer for each question. For this particular app, you are passing two questions, the first one to ask for the first name and the second one to ask for the operations to perform.</p>
<p>The first name is a regular input field where the user can type in an answer. The important part is you are using a <code>validate</code> function to make sure that the first name is between 3 and 20 characters. Other checks could have been done here like the first name cannot be numeric. Another feature you have used is the <code>filter</code> function that filters the value sent in by the user. The filter function here trims out any spaces before or after the answer, this means if the user input <code> liam </code> it will result in <code>liam</code> trimming the spaces entered by the user before and after the input.</p>
<p>Next, you are asking the user for the choice of <code>gender</code> and/or <code>nationality</code>. Hence the choices option is used with two values accordingly. The <code>validate</code> function in this question makes sure that at least one of the two options is selected before going on. If you do not select any option the app will look like the below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/inquirer-js/03inquirer-js-validation.jpg" title="Example of validation in Inquirer.js" alt="Example of validation in Inquirer.js" />
<p>And when you have entered the right values the app will go ahead and log the answers array.<br />
You can save the above file as <code>answers.js</code> and run it with <code>node answers.js</code> command. You can view the full code of this file on <a href="https://github.com/geshan/inquirer-demo/blob/master/answers.js">GitHub</a> too. As you have the required input from the user, next you will write the code to call the free APIs to guess the gender and nationality of the provided first name.</p>
<h3 id="code-to-guess-gender-and-nationality-calling-apis" tabindex="-1">Code to guess gender and nationality calling APIs <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#code-to-guess-gender-and-nationality-calling-apis">#</a></h3>
<p>In this section, you will write the code to fetch the gender and nationality guesses for the given first name from the respective APIs.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">guessGender</span><span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.genderize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> <span class="token punctuation">{</span> gender<span class="token punctuation">,</span> probability <span class="token punctuation">}</span> <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The API guessed the gender for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to be </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>gender<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token punctuation">(</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">% probability</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">guessNationality</span><span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.nationalize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> <span class="token punctuation">{</span> country <span class="token punctuation">}</span> <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>country <span class="token operator">||</span> <span class="token operator">!</span>country<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The API could not guess the nationality for the name </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token comment">//can use this API to get country name from ISO 2 - http://api.worldbank.org/v2/country/np?format=json</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The API guessed the nationality for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to be </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>country<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>country_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with the highest probability of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token punctuation">(</span>country<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>There are two functions in the above code block. The first one is <code>guessGender</code> which calls the <code>genderize.io</code> API passing the first name to guess the gender. It uses the <a href="https://axios-http.com/">Axios</a> package to make the HTTP Get call. Axios is a popular promise-based HTTP client that can be used in both Node.js and the browser. To make this call more resilient you can use <a href="https://geshan.com.np/blog/2022/11/axios-timeout/">Axios Timeout</a> too. From the response body, it plucks out the <code>gender</code> and the <code>probability</code> using destructuring to use it in the log to print out the guessed gender of the given first name with its probability. The <code>toFixed</code> method is used in the log to show an output like <code>95.74%</code> in place of <code>95.7537437%</code>.</p>
<p>Next, you have coded the <code>guessNationality</code> function that does a similar thing by doing an HTTP Get call on the <code>nationalize.io</code> API using Axios. This API returns an array of countries with its probability for nationality. From this list, as it is sorted with the highest probability first, you pick the first country and print its <code>id</code> (which is the ISO2 code) and the probability with a <code>toFixed</code> formatting. In the next section, you will join up the above two code pieces to have a fully functioning CLI application to get the first name and guess the gender and/or nationality of that first name.</p>
<h3 id="sew-up-everything-together" tabindex="-1">Sew up everything together <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#sew-up-everything-together">#</a></h3>
<p>At this juncture, you will piece together all the above code to form the working CLI application. The full application with fetching the answers from the user and calling the APIs looks as follows:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><br /><span class="token keyword">import</span> inquirer <span class="token keyword">from</span> <span class="token string">'inquirer'</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> answers <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getAnswers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Calling API(s) might take some time...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">const</span> option <span class="token keyword">of</span> answers<span class="token punctuation">.</span>options<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>option <span class="token operator">===</span> <span class="token string">'gender'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">await</span> <span class="token function">guessGender</span><span class="token punctuation">(</span>answers<span class="token punctuation">.</span>firstName<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>option <span class="token operator">===</span> <span class="token string">'nationality'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">await</span> <span class="token function">guessNationality</span><span class="token punctuation">(</span>answers<span class="token punctuation">.</span>firstName<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /> <br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">There was an error while talking to the API: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token punctuation">.</span>message<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">getAnswers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> inquirer<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'firstName'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What is your first name?'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'input'</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">validate</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>firstName<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Please provide a first name'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">if</span><span class="token punctuation">(</span>firstName<span class="token punctuation">.</span>length <span class="token operator"><=</span> <span class="token number">3</span> <span class="token operator">||</span> firstName<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Please provider a first name between 4 and 20 characters long'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> firstName<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'options'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What would you like to guess for the given first name?'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'checkbox'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">choices</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'gender'</span><span class="token punctuation">,</span> <span class="token string">'nationality'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">validate</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>options<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Choose at least one of the above, use space to choose the option'</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">guessGender</span><span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.genderize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> <span class="token punctuation">{</span> gender<span class="token punctuation">,</span> probability <span class="token punctuation">}</span> <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The API guessed the gender for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to be </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>gender<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token punctuation">(</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">% probability</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">guessNationality</span><span class="token punctuation">(</span><span class="token parameter">firstName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.nationalize.io/?name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> <span class="token punctuation">{</span> country <span class="token punctuation">}</span> <span class="token operator">=</span> response<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>country <span class="token operator">||</span> <span class="token operator">!</span>country<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The API could not guess the nationality for the name </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token comment">//can use this API to get country name from ISO 2 - http://api.worldbank.org/v2/country/np?format=json</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The API guessed the nationality for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to be </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>country<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>country_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with the highest probability of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token punctuation">(</span>country<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>probability <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>While sewing up the code, the new thing that has been added is how the answers are parsed in the async IIFE. After the answers have been collected, a log is added to notify the user that API(s) are being called which can take some time. Then you loop through each of the options in the <code>answer.options</code> array. If the option is <code>gender</code> you call the <code>guessGender</code> function by passing the first name. Similarly, if the option is <code>nationality</code> you call the <code>guessNationality</code> function again passing the first name. For all function calls of <code>getAnswers</code>, <code>guessGender</code>, and <code>guessNationalty</code> they are wrapped in a try, catch so that in case of any error it is logged.</p>
<p>All the code is available in a <a href="https://github.com/geshan/inquirer-demo">GitHub repository</a> for your reference, the above <a href="https://github.com/geshan/inquirer-demo/blob/master/index.js">file</a> is also included. You can use other options available on Inquirer.js too like <a href="https://github.com/SBoudrias/Inquirer.js/#list---type-list">list</a>, <a href="https://github.com/SBoudrias/Inquirer.js/#expand---type-expand">expand</a> and <a href="https://github.com/SBoudrias/Inquirer.js/#confirm---type-confirm">confirm</a> types as per need.</p>
<p>You can run the final code by executing <code>node index.js</code> which will look like the following:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/inquirer-js/02inquirer-js-app-demo.gif" title="Running CLI app built with Inquirer.js in Node.js" alt="Running CLI app built with Inquirer.js in Node.js" />
<p>Hurray! You have built a running CLI application in Node.js using Inquirer.js and also used important features of the library like validation and filter in the process. You can run multiple commands with <a href="https://geshan.com.np/blog/2022/09/npm-concurrently/">NPM concurrently</a> or try <a href="https://geshan.com.np/blog/2022/07/javascript-promise-all/">JavaScript Promise all</a> for a similar effect programatically.</p>
<p>You might not know that Inquirer.js is one of the most popular Node.js NPM libraries to build CLI apps much more used than the native <a href="https://geshan.com.np/blog/2022/03/nodejs-readline/">Node.js readline</a>, that is what you will find out next.</p>
<h2 id="popularity-of-inquirer.js" tabindex="-1">Popularity of Inquirer.js <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#popularity-of-inquirer.js">#</a></h2>
<p>Inquirer.js is one of the most popular NPM libraries to write a CLI application in Node.js. As per <a href="https://npmtrends.com/enquirer-vs-inquirer-vs-prompt-vs-prompts">NPM trends</a> it has been downloaded almost 28.5 million times in the week ending 12-Mar-2023 as seen below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/inquirer-js/04inquirer-js-popularity.jpg" title="With almost 28.5 million downloads per week, Inquirer.js is pretty popular" alt="With almost 28.5 million downloads per week, Inquirer.js is pretty popular" />
<p>It was created 10 years ago and has over 17.6K stars. It is not as popular as <a href="https://github.com/tj/commander.js">commander.js</a> but has the advantage of being a bit simple and supporting Promises. Another advantage is the plugin architecture of Inquirer.js discussed in the next section.</p>
<h2 id="inquirer.js-plugins" tabindex="-1">Inquirer.js plugins <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#inquirer.js-plugins">#</a></h2>
<p>Inquirer.js has a plugin-enabled architecture and there are many <a href="https://github.com/SBoudrias/Inquirer.js#plugins">plugins</a> available. For instance, you could make the output colorful using the [NPM chalk] package pipe <a href="https://github.com/LitoMore/inquirer-chalk-pipe">plugin</a> with Inquirer. Similarly, you could also use make use of the <a href="https://github.com/mokkabonna/inquirer-autocomplete-prompt">auto complete</a>, <a href="https://github.com/DerekTBrown/inquirer-datepicker-prompt">data time</a> and even <a href="https://github.com/tannerntannern/inquirer-emoji">emoji</a> plugins.</p>
<p>The plugins ecosystem makes Inquirer.js a more interesting option in comparison to other options.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/03/inquirer-js/#conclusion">#</a></h2>
<p>In this tutorial, you learned how to create a simple yet complete and useful CLI application in Node.js using Inquirer.js which can guess the gender and nationality of a given first name by calling a couple of APIs. You also used advanced features of Inquirer.js like validation and filter. Then you were informed about the enormous popularity of Inquirer.js and its useful plugins.</p>
<p>I hope you learned something new and how to build a useful CLI application in Node.js using Inquirer.js.</p>
How to use React fragments, a step-by-step guide for beginners2023-02-28T12:28:57Zhttps://geshan.com.np/blog/2023/02/react-fragments/<p>React is one of the most popular JavaScript libraries. React fragments solves the problem of returning multiple elements without the need of wrapping them in an extra Node (usually a div).</p>
<p>The fragments feature was introduced in v <a href="https://github.com/facebook/react/blob/main/CHANGELOG.md#react-17">16.2</a> of <a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html">React</a>. In this tutorial, you will learn how to use React fragments to add multiple elements to a React component, let’s get started!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-fragments/01react-fragments.jpg" title="Learn how to use React fragments to return multiple HTML elements from React components" alt="Learn how to use React fragments to return multiple HTML elements from React components" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/02/react-fragments/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/02/react-fragments/#what-are-react-fragments%3F">What are React fragments?</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/react-fragments/#example-app---hackernews">Example App - HackerNews</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/02/react-fragments/#the-problem-when-not-using-react-fragments">The problem when not using React fragments</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/02/react-fragments/#react-fragments-solve-this-problem">React fragments solve this problem</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/react-fragments/#conclusion">Conclusion</a></li>
</ul>
<h2 id="what-are-react-fragments%3F" tabindex="-1">What are React fragments? <a class="direct-link" href="https://geshan.com.np/blog/2023/02/react-fragments/#what-are-react-fragments%3F">#</a></h2>
<p>React <a href="https://reactjs.org/docs/fragments.html">fragments</a> is a feature included in React to return more than one HTML element from a React Component. It is a common pattern in React for a component to return multiple elements, but with the usual React component syntax and return, it always expects only a single HTML element to be returned. To comply with this requirement, React developers usually wrap the HTML with an extra div element.</p>
<p>On the other hand, fragments let you group a list of children without adding extra nodes (HTML Elements) to the DOM, which results in a shallow DOM tree.</p>
<h2 id="example-app---hackernews" tabindex="-1">Example App - HackerNews <a class="direct-link" href="https://geshan.com.np/blog/2023/02/react-fragments/#example-app---hackernews">#</a></h2>
<p>For this guide, you will use an existing simple React application. It uses the unofficial HackerNews API provided by <a href="https://hn.algolia.com/api">Algolia</a> to get the Hackernews front-page stories. The app is built on React 18.2 and below is the screenshot of the app in action:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-fragments/02hackernews-stories.jpg" title="A simple react App to show the latest front-page stories from HackerNews" alt="A simple react App to show the latest front-page stories from HackerNews" />
<p>You can find the app running on <a href="https://hackernews-react-fragment.netlify.app/">Netlify</a> and the code is available on <a href="https://github.com/geshan/hackernews-react">GitHub</a> for your reference.</p>
<p>If you look at the <a href="https://github.com/geshan/hackernews-react/blob/before-react-fragments/src/HackerNewsStories.js">HackerNewsStories</a> component the code looks as follows:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">HackerNewsStories</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> <span class="token punctuation">[</span>stories<span class="token punctuation">,</span> setStories<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> <span class="token punctuation">[</span>error<span class="token punctuation">,</span> setError<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> <span class="token function-variable function">fetchStories</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'https://hn.algolia.com/api/v1/search_by_date?tags=front_page&hitsPerPage=20'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">setStories</span><span class="token punctuation">(</span><br /> data<span class="token punctuation">.</span>hits<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">story<span class="token punctuation">,</span> nextStory</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>story<span class="token punctuation">.</span>points <span class="token operator"><</span> nextStory<span class="token punctuation">.</span>points <span class="token operator">?</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">setError</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">setError</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">setStories</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span><br /> <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /> <span class="token function">fetchStories</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"wrapper"</span><span class="token operator">></span><br /> <span class="token operator"><</span>h2<span class="token operator">></span>Latest <span class="token constant">HN</span> Stories<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span><br /> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span>HackerNews frontpage stories loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br /> <span class="token punctuation">{</span>error <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Problem fetching the HackeNews Stories - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>error<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"stories-wrapper"</span><span class="token operator">></span><br /> <span class="token punctuation">{</span>stories <span class="token operator">&&</span><br /> stories<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> objectID<span class="token punctuation">,</span> url<span class="token punctuation">,</span> title<span class="token punctuation">,</span> author<span class="token punctuation">,</span> points <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br /> title <span class="token operator">&&</span> url <span class="token operator">&&</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'stories-list'</span> key<span class="token operator">=</span><span class="token punctuation">{</span>objectID<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>h3<span class="token operator">></span><span class="token operator"><</span>a href<span class="token operator">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span> target<span class="token operator">=</span><span class="token string">"_blank"</span> rel<span class="token operator">=</span><span class="token string">"noreferrer"</span><span class="token operator">></span><span class="token punctuation">{</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator">-</span> By <span class="token operator"><</span>b<span class="token operator">></span><span class="token punctuation">{</span>author<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>b<span class="token operator">></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>points<span class="token punctuation">}</span> points<span class="token punctuation">)</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <br /> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">export</span> <span class="token keyword">default</span> HackerNewsStories<span class="token punctuation">;</span></code></pre>
<p>Let’s say due to the design need or to have lesser depth in the DOM tree you want to remove the div with the class <code>wrapper</code>. Do you think you can just remove that parent div?</p>
<h3 id="the-problem-when-not-using-react-fragments" tabindex="-1">The problem when not using React fragments <a class="direct-link" href="https://geshan.com.np/blog/2023/02/react-fragments/#the-problem-when-not-using-react-fragments">#</a></h3>
<p>No, because React components do not support returning multiple HTML elements. On the line just below the return you see <code><div className="wrapper"></code> which is an extra div that is an extra HTML Node used. It is needed, if you try to remove it you will get an error. For instance, if you change the above return part to the following code to remove the div with class wrapper:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span><br /> <span class="token operator"><</span>h2<span class="token operator">></span>Latest <span class="token constant">HN</span> Stories<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span><br /> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span>HackerNews frontpage stories loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br /> <span class="token punctuation">{</span>error <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Problem fetching the HackeNews Stories - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>error<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"stories-wrapper"</span><span class="token operator">></span><br /> <span class="token punctuation">{</span>stories <span class="token operator">&&</span><br /> stories<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> objectID<span class="token punctuation">,</span> url<span class="token punctuation">,</span> title<span class="token punctuation">,</span> author<span class="token punctuation">,</span> points <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br /> title <span class="token operator">&&</span> url <span class="token operator">&&</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'stories-list'</span> key<span class="token operator">=</span><span class="token punctuation">{</span>objectID<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>h3<span class="token operator">></span><span class="token operator"><</span>a href<span class="token operator">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span> target<span class="token operator">=</span><span class="token string">"_blank"</span> rel<span class="token operator">=</span><span class="token string">"noreferrer"</span><span class="token operator">></span><span class="token punctuation">{</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator">-</span> By <span class="token operator"><</span>b<span class="token operator">></span><span class="token punctuation">{</span>author<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>b<span class="token operator">></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>points<span class="token punctuation">}</span> points<span class="token punctuation">)</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <br /> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>It will result in the following error:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-fragments/03no-react-fragments-error.jpg" title="Error in React while trying to return multiple HTML elements without using React fragments" alt="Error in React while trying to return multiple HTML elements without using React fragments" />
<p>Basically, it means you cannot return more than one HTML element from a React Component. This is the problem solved by React fragments, which will be discussed next.</p>
<h2 id="react-fragments-solve-this-problem" tabindex="-1">React fragments solve this problem <a class="direct-link" href="https://geshan.com.np/blog/2023/02/react-fragments/#react-fragments-solve-this-problem">#</a></h2>
<p>To solve this problem of returning more than one HTML element from a React component without wrapping it with another HTML tag/element like a div, you can use React fragments. The same return after using React fragment to return multiple HTML elements will look like the below:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">return</span> <span class="token punctuation">(</span><br /> <span class="token operator"><</span>Fragment<span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* You can also use the shorter syntax of <> */</span><span class="token punctuation">}</span> <br /> <span class="token operator"><</span>h2<span class="token operator">></span>Latest <span class="token constant">HN</span> Stories<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span><br /> <span class="token punctuation">{</span>loading <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span>HackerNews frontpage stories loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br /> <span class="token punctuation">{</span>error <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Problem fetching the HackeNews Stories - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>error<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"stories-wrapper"</span><span class="token operator">></span><br /> <span class="token punctuation">{</span>stories <span class="token operator">&&</span><br /> stories<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> objectID<span class="token punctuation">,</span> url<span class="token punctuation">,</span> title<span class="token punctuation">,</span> author<span class="token punctuation">,</span> points <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br /> title <span class="token operator">&&</span> url <span class="token operator">&&</span><br /> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">'stories-list'</span> key<span class="token operator">=</span><span class="token punctuation">{</span>objectID<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>h3<span class="token operator">></span><span class="token operator"><</span>a href<span class="token operator">=</span><span class="token punctuation">{</span>url<span class="token punctuation">}</span> target<span class="token operator">=</span><span class="token string">"_blank"</span> rel<span class="token operator">=</span><span class="token string">"noreferrer"</span><span class="token operator">></span><span class="token punctuation">{</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator">-</span> By <span class="token operator"><</span>b<span class="token operator">></span><span class="token punctuation">{</span>author<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>b<span class="token operator">></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>points<span class="token punctuation">}</span> points<span class="token punctuation">)</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <br /> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br /> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token punctuation">{</span><span class="token comment">/* </> is the closing tag for shorter React fragment syntax */</span><span class="token punctuation">}</span><br /> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>For this to work, you will need to import <code>Fragment</code> from react at the top of the component as follows:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span></code></pre>
<p>The above React component now returns 2 or 3 HTML elements, one H2, one of the two divs for loading or error, and the last div which will render the stories with the CSS class <code>stories-wrapper</code>. You have easily solved the problem and it is possible to return more than one HTML element from a React component now.</p>
<p>As seen above you can use the full React fragment syntax or the short syntax with just <code><></code> and <code></></code>. You will need to use the full syntax if you want to make use of <a href="https://reactjs.org/docs/fragments.html#keyed-fragments">Keyed fragments</a>, where every fragment has a unique key.</p>
<p>To better understand the HTML structure, below is the comparison between before using React fragments with a <code>div</code> wrapper and after using React fragments is shown below:</p>
<img class="center" loading="lazy" src="https://geshan.com.np/images/react-fragments/04react-fragments-html.jpg" title="Making the HTML simpler by using React fragments" alt="Making the HTML simpler by using React fragments" />
<p>It has multiple advantages, for instance, the depth of the HTML node tree will be lesser. In addition to that if you are creating a subcomponent structure like an HTML table you can get the exact HTML you are after. Also if you have a style sheet targeting elements by their depth, they will work without any change as the HTML will not have any extra layer of div or other HTML elements.</p>
<p>The code change demonstrated in this blog post is available as a <a href="https://github.com/geshan/hackernews-react/pull/7">pull request</a> for your reference. You can also see the app running with react fragments on <a href="https://deploy-preview-7--hackernews-react-fragment.netlify.app/">Netlify</a>. Start using React fragments now.</p>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/02/react-fragments/#conclusion">#</a></h2>
<p>In this guide, you learned what React fragments are. Then you were introduced to a problem of trying to return multiple HTML elements from a regular React Component which got stuck due to an error. Then you employed React fragments to get over the problem and with an easy-to-use Syntax you were able to return multiple elements for a React Component.</p>
<p>I hope you learned something new after reading this, keep learning!</p>
5 similarities between software systems and being married (read with a pinch of salt)2023-02-22T11:47:55Zhttps://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/<p>Software systems and marriages have many things in common and there are differences too. In this post, you will learn about 5 things that are similar in both software systems and marriages, let’s get going!</p>
<!-- more -->
<img class="center" loading="lazy" src="https://geshan.com.np/images/software-systems-marriages/01software-systems-marriages.jpg" title="Similarities between software systems and being married" alt="Similarities between software systems and being married" />
<h2 id="table-of-contents" tabindex="-1">Table of contents <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#table-of-contents">#</a></h2>
<ul>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#so-you-said-software-systems-and-married-life%2C-hmm...">So you said software systems and married life, hmm...</a>
<ul>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#the-first-2-years-seem-to-be-good%2C-but-then-the-real-fun-starts">The first 2 years seem to be good, but then the real fun starts</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#housekeeping-is-essential">Housekeeping is essential</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#cap-theorem---marriage-version">CAP theorem - marriage version</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#try-new-things-but-never-forget-the-basics">Try new things but never forget the basics</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#union-of-2-families-not-just-2-individuals">Union of 2 families not 2 just individuals</a></li>
</ul>
</li>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#other-common-things">Other common things</a></li>
<li><a href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#conclusion">Conclusion</a></li>
</ul>
<h2 id="so-you-said-software-systems-and-married-life%2C-hmm..." tabindex="-1">So you said software systems and married life, hmm... <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#so-you-said-software-systems-and-married-life%2C-hmm...">#</a></h2>
<p>Yes, you will learn about the similarities between a marital relationship and a software system. It will go deeper than the usual stuff of both needing careful planning, effective communication, continuous maintenance, flexibility, and trust. Even ChatGPT will give you those points and elaborate on them. To be clear, by software systems I mean web applications that talk to a datastore (read relational database) and have <a href="https://geshan.com.np/blog/2020/12/software-scalability/">software scalability</a>. These systems are expected to demonstrate <a href="https://geshan.com.np/blog/2020/12/software-resilience/">software resilience</a> too.</p>
<p>I have been writing software professionally for more than 15 years now and have been happily married for more than a decade. I guess by now I know a thing or two about both software systems and marital relationships. Of course, the part about marriage will have some (dark) humor with it. You must read it with a grain/pinch of salt. Below are the factors that are common between software systems and marriages.</p>
<h3 id="the-first-2-years-seem-to-be-good%2C-but-then-the-real-fun-starts" tabindex="-1">The first 2 years seem to be good, but then the real fun starts <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#the-first-2-years-seem-to-be-good%2C-but-then-the-real-fun-starts">#</a></h3>
<p>Both new software systems and new marriages seem to work well for the first 2 years or a bit less. You are permitted to call it the <a href="https://www.brides.com/honeymoon-phase-5097161">honeymoon phase</a> at your own risk. Then the friction and rust start to appear.</p>
<p>Every software ever written has a life. The average software engineer like us writes software that works well for around 5 years then it has its own share of problems. The first 1-2 years it will have fewer issues. Issues are less also because the data the software has to deal with is less for the first couple of years.</p>
<p>The problems usually start with being tagged as “legacy” software after a couple of years. After 5+ years, some software systems are barely breathing but more oxygen (resources) are pumped to them to keep them functioning.</p>
<blockquote>
<p>The point here is to make time for refactoring and rewriting parts or whole systems if needed.</p>
</blockquote>
<p>Given that is done the software systems will serve you well else they might become the problem child that triggers calls at 3 AM in the morning.</p>
<p>You might be asking how it is common with marriages, look at a couple who married a couple of months back and a couple who has been married for 12 years with 2 kids. You will find your answers. I digress and will let you do your own mental analysis :D. Where do you see the spark in the first couple or the second with 2 kids?</p>
<h3 id="housekeeping-is-essential" tabindex="-1">Housekeeping is essential <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#housekeeping-is-essential">#</a></h3>
<p>Housekeeping is essential in both marriages and software systems. For example, in software systems, you should periodically upgrade dependencies.<br />
if you do not periodically upgrade your dependencies managed by a package manager like NPM, Composer, PIP, etc then when the time comes to upgrade,<br />
many of these packages at once it becomes a big headache.</p>
<p>The same thing happens with other things in software systems like the version of your language/runtime or framework not being updated for long. Some code refactoring or rewriting (read tech debt) left as is for a long time. All these are bad housekeeping practices that will bite you soon. The issue is exacerbated when you have an issue and these kinds of issues become a blocker to solving the issue.</p>
<blockquote>
<p>The easy solution here is to keep the changes small and keep doing them consistently.</p>
</blockquote>
<p>Not doing the housekeeping chores in the house will breed the same problems. Yes, you need to clean on top of the fridge and mop the floor too. These things are required for a long successful marriage. Try this experiment, don’t vacuum your home for 3 weeks. It will cause more issues in your marital relationship than the layers of dust on the showpiece.</p>
<h3 id="cap-theorem---marriage-version" tabindex="-1">CAP theorem - marriage version <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#cap-theorem---marriage-version">#</a></h3>
<p>In software systems, for data stores, there is a popular theorem abbreviated as <a href="https://www.educative.io/blog/what-is-cap-theorem">CAP Theorem</a> by Eric Brewer. The CAP here stands for Consistency, Availability, and Partition tolerance and the theorem states you can have 2 of these three. So either CA, CP, or AP.</p>
<blockquote>
<p>For instance relational databases like MySQL, PostgreSQL are CA (Consistent and Available) but not partition tolerant meaning if there is an issue with the connection it will fail.</p>
</blockquote>
<p>On the other hand MongoDB has Consistency and Partition tolerance (CP) but lacks availability due to its primary node election process. Similarly, AWS DynamoDB has Availability and Partition tolerance (AP) and lacks consistency due to its design, it goes with eventual consistency.</p>
<p>There is a 3 factor reality in Project management, it is <a href="https://support.microsoft.com/en-us/office/the-project-triangle-8c892e06-d761-4d40-8e1f-17b33fdcf810">fast, good, cheap</a> and you have to choose any 2.</p>
<p>Coming back to the point, a similar CAP theorem applies to marital relationships too, where C and A are Consistency, Availability but P is Patience and you have to choose 2. If your wife is Consistent and available she will not be Patient. If your husband is Consistent and Patient, he will not be available. If your wife is available and patient she will not be consistent. Humans are complex so you may get all 3 of CAP but only in the first 2 years of your relationship :D haha. What does all this mean? Draw your own meanings out of this, I give you full liberty ;).</p>
<h3 id="try-new-things-but-never-forget-the-basics" tabindex="-1">Try new things but never forget the basics <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#try-new-things-but-never-forget-the-basics">#</a></h3>
<p>In both a software system and marital relationship you have to be strong in your basics as pointed out in one of my <a href="https://geshan.com.np/blog/2017/02/things-i-wished-i-knew-as-a-junior-developer-slides/">talks</a>. Being strong in the basics for software systems include knowing your datastore well, understanding the fundamentals of networking/HTTP, having knowledge about how the browser works etc. These things are indispensable for a software engineer that works with web applications.</p>
<p>Once the basics are covered well you can wander off bravely to try out the new language and framework.</p>
<blockquote>
<p>If you don’t understand why you need a framework just changing the framework or language is not going to help you.</p>
</blockquote>
<p>You can experiment with new tools (read toys) for side projects but for production grade systems always <a href="https://boringtechnology.club/">choose boring technology</a>. Decide to use things your team has already worked with and has good experience with. Do it because when things hit the fan, you can work as a team and fix the bug much faster compared to having Rust or that new framework on production.</p>
<p>The same formula applies for marriage. Keep it simple, be there with your partner in need. Behave in a culturally apt way and stick to the basics. Once the basics are in place then do experiments or new things. Even with that don’t rock the boat too much. You are very smart as you are reading this, a happy wife = a happy life, period.</p>
<h3 id="union-of-2-families-not-just-2-individuals" tabindex="-1">Union of 2 families not just 2 individuals <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#union-of-2-families-not-just-2-individuals">#</a></h3>
<p>Marriage might look like an association of two human beings from the outside. Alas! It is much more than that behind the curtains. It is a union of 2 families, the bride and groom’s family. This phenomenon is accentuated in South Asia where it is common to have 500+ people attending (read many overeating and some getting drunk) wedding parties.</p>
<p>In the software systems land, these two families are the customers and the builders. Customers/users of the system are self explanatory. They can be divided into internal (employees) or external (customers/users).</p>
<p>The builder's family has a wide range of skills in it. There are software engineers (backend and frontend), designers, platform (read cloud or devops) engineers, product managers, probably mobile engineers and QA engineers. These days there are other data roles as well like data analyst, data engineer and data scientist. These folks help extract insights from data. Let's not even venture to the Machine Learning/AI part.</p>
<p>The PM and UX researchers are the interface through which customers talk to the company. Still, this long running association doesn’t have the star bride and groom as such but needs to keep the family of the bride (or groom, depending on the culture), which is the customer is always a priority.</p>
<blockquote>
<p>The main point here is to take care of the other family’s members. In a marital relationship lookout and help your partner’s family members as you would do for your own.</p>
</blockquote>
<p>Similarly in software systems, the customer’s valid needs should always get the priority it deserves.</p>
<h2 id="other-common-things" tabindex="-1">Other common things <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#other-common-things">#</a></h2>
<p>There are other common things between software systems and being married. For instance the only thing constant in both systems is change. Technology is not permanent and getting married also demands an array of changes in your life. In both software systems and marriage learn to celebrate small wins. This helps boost self confidence and build more trust. Being clear in communication helps a lot in both systems. Always practice clear and concise communication tailored to the audience and delivered via the right channel.</p>
<h1 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://geshan.com.np/blog/2023/02/software-systems-being-married-similarities/#conclusion">#</a></h1>
<p>There you have it, a fun read about the similarities between software systems and marital relationships. So to sum up, marital relationships are similar to software systems. Both run well for the first 2 years then start showing their true colors. Both of them need continuous housekeeping or you will get a burnt smell.</p>
<p>Both software systems and marriages have a CAP theorem with a different P :). You have to be strong in the basics for both to try our new things. Finally both marriages and software systems are a union of 2 families and there is always a delicate balance to maintain.</p>
<blockquote>
<p>Knowing about these similarities you should be able to predict and debug issues in software systems (and complex marital relationships) much better now.</p>
</blockquote>
<p>You have to be on your toes for both the systems most of the time. The good thing is for software systems you can measure, monitor and send alerts if things are not right. For the being married part you wished those things were possible :D.</p>
<p>Again, take this with a pinch of salt and I hope you enjoyed this lighthearted read.</p>