<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dhruv Nakum]]></title><description><![CDATA[I'm a mobile/web developer 👨‍💻 who loves to build projects and share valuable tips for programmers.
Follow me for Flutter, React/Next.js, and other awesome te]]></description><link>https://dhruvnakum.xyz</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1637753624766/fZ6HW1zPF.png</url><title>Dhruv Nakum</title><link>https://dhruvnakum.xyz</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Apr 2026 14:29:27 GMT</lastBuildDate><atom:link href="https://dhruvnakum.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Diving into Docker (Part 7): Docker Swarm]]></title><description><![CDATA[If you are still following along, I must say that a few people have come this far. And let me congratulate you because it's been a long journey, and I am sure you have learned many new things so far. ]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-7-docker-swarm</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-7-docker-swarm</guid><category><![CDATA[Docker]]></category><category><![CDATA[docker swarm]]></category><category><![CDATA[Multi-Service Business Routers (MSBRs) Market Growth]]></category><category><![CDATA[containers]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Mon, 16 Mar 2026 22:31:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/073cd526-0c72-4550-97ad-02a9add22ab2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you are still following along, I must say that a few people have come this far. And let me congratulate you because it's been a long journey, and I am sure you have learned many new things so far. We went from knowing the difference between VMs and Containers to running them and deploying to the Docker Hub. We learned about docker-compose too, which is used in production to deploy multi-service applications.</p>
<p>But if you see, till now, we were dealing with a single host and a few containers. But in real life, that is not the case. In companies, they have so many products and services, and those services do not run on a single host. They are scattered around the world or in other places. Then you might ask, who manages those services? Is it like someone sitting in front of the display and checking all the time which services are working correctly or not?</p>
<p>If you think that is how they manage, you are mistaken, because managing so many services manually is not possible today. So what's the solution? Who manages it?</p>
<p>To answer that, you have to read this blog. But if you don't want to and just want to know, then here is the short answer:</p>
<p><strong>Docker Swarm / Kubernetes</strong></p>
<p>I bet you want more details than just these two words, right? And to get that, you'll have to read the blog, so, sorry, 😅 I can't give you the short answer. Because, like life, there are no shortcuts to achieving goals. Okay, enough of motivation, let's get to the real thing.</p>
<hr />
<h2>Docker Swarm</h2>
<p>We now know how to install Docker, pull images, and work with containers. But as we discussed above, to work with that big scale, we need something that can manage these containers for us. And that's where <strong>Docker Swarm</strong> comes into the picture.</p>
<h3>What is Docker Swarm?</h3>
<p>Docker Swarm is a tool that helps you manage multiple Docker machines. Instead of running containers on just one computer, you can connect multiple machines and treat them like a big system. This group of machines is called a <strong>cluster.</strong></p>
<p>In a Swarm cluster, each machine is called a <strong>node.</strong> A node can be a physical server, a virtual machine, a cloud server, or even a small device like a Raspberry Pi. The only thing required is that Docker must be installed, and the machines must be able to talk to each other over the network.</p>
<h3>Types of Node</h3>
<p>There are two types of nodes: <strong>managers</strong> and <strong>workers</strong>.</p>
<p><strong>Managers</strong> control the cluster. They decide what tasks should run and which worker should run them.</p>
<p><strong>Workers</strong> are the machines that actually run the containers and do the work. Managers tell them what to do, and workers follow those instructions.</p>
<p>Docker Swarm also keeps track of the cluster’s information, like which containers are running and which nodes are available. This information is stored on the manager nodes in a distributed database. The nice thing is that Docker sets this up automatically, so you don’t need to configure it yourself.</p>
<p>If you are concerned about Docker's security, then don't. Because security is built into Swarm. Communication between nodes is encrypted, and each node must prove its identity before joining the cluster. Docker also automatically manages and rotates security certificates, so the system stays secure without extra effort.</p>
<p>Swarm is also used to run and manage applications made of many small services called <strong>microservices</strong>. In Swarm, the main unit used to run applications is called a <strong>service</strong>. A service is similar to a container but with extra features. For example, you can easily run multiple copies of it, update it gradually without downtime, or roll back to an older version if something breaks.</p>
<blockquote>
<p>There is also one tool called <strong>Kubernetes</strong> which is a competitor of Docker Swarm. They both orchestrate containerized applications. Well, it's true that Kubernetes is more popular and have more active community and ecosystem. Docker Swarm has it's own benefits too. It's a lot easier to configure and deploy. While it may not be the best solution for bigger companies, but its an excellent technology for small to medium businesses.</p>
</blockquote>
<p>I think that's enough of the theory. Let's get to the practical part and see how we can implement this ourselves.</p>
<hr />
<h2>Creating our OWN Swarm Cluster</h2>
<p>The example is highly inspired by the book (Docker Deep Dive - Nigel Poulton). The only thing missing there was that he didn't show how to implement it with a single host machine. Because hey, for just the example, we're not gonna have 10 different machines and run and test it, right? So what I did was, I implemented the same thing with the help of <strong>AWS.</strong> Let's see how we can implement it. The only prerequisite is to have an AWS account. So if you don't have one, I would suggest to make one. I am not gonna show it here otherwise the blog will become lengthy. So make one and then start from here.</p>
<h3>Example:</h3>
<p>So, in the example, we are going to make a secure swarm cluster with <strong>one manager nodes</strong> and <strong>two worker nodes</strong>.</p>
<p>As we saw earlier, that nodes can be virtual machines, physical servers, cloud instances (in our case), or Raspberry Pi systems. The only thing required on those system is to have Docker installed.</p>
<h3>Creating 3 EC2 instances ( 1 manager, 2 worker)</h3>
<p>Go to <a href="https://signin.aws.amazon.com/signin">https://signin.aws.amazon.com/signin</a> and sign in with the <strong>Root user</strong>. Once you are in, you will see a dashboard like this.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/99bd4b99-5733-45b4-932d-432fa01c88f8.png" alt="" style="display:block;margin:0 auto" />

<p>Now we need 3 machines, right? So let's create 3 EC2 instances. Go or search for EC2 and get in.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/0d251db0-48cf-4dcb-bef6-a930143ec6c1.png" alt="" style="display:block;margin:0 auto" />

<p>Now, click on <strong>Launch instance.</strong></p>
<h4>Creating Manager Node</h4>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/6b9e4401-e63a-429e-919a-ac32ac95ce62.png" alt="" style="display:block;margin:0 auto" />

<p>Now, we need to name our machine and configure some options.</p>
<blockquote>
<p>If you don't know anything about AWS EC2, I think it's the best time to learn. Because in today's time, it good to have some knowledge about it at-least if not a hands on experience. But anyways, you will not be needing to know much about it for this example as it's gonna be really simple.</p>
</blockquote>
<blockquote>
<p>Here, we are doing nothing but creating a Virtual instances (machines) for us to be able to test Docker Swarm capabilities.</p>
</blockquote>
<p>Let's now finish the configuration part. Go ahead and name this instance <strong>"mgr1"</strong> (this will be our manager). Then select the <strong>Ubuntu</strong> image</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/01833796-943e-493a-8bfc-69c3c8138669.png" alt="" style="display:block;margin:0 auto" />

<p>After that, we need to add a key pair. This is required as we are gonna connect this instance to our laptop's terminal and use it. So go ahead and create an RSA (.pem) private key and store it somewhere safe. I named this key <strong>docker-swarm-test.</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/56fcdab7-3c64-44ee-ac53-0e2949630d0f.png" alt="" style="display:block;margin:0 auto" />

<p>Once this is done, do nothing, just click on <strong>Launch Instance</strong>. As you can see below, we now have the running manager instance.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/3d8da1be-d193-49ef-a14a-a17554ab03af.png" alt="" style="display:block;margin:0 auto" />

<p>Now, we don't need to open these instances to the whole world, right? So what we do is we open a few ports between these instances for them to talk. We can add those ports by going into the <strong>Security</strong> section. Click on the <strong>Security Group link</strong>, it will redirect you to the new page where we can add the ports</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/decb7897-d7cd-49eb-8a63-68844a7604e8.png" alt="" style="display:block;margin:0 auto" />

<p>Click the <strong>"Edit Inbound rules"</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/572f1421-ed5e-4310-8a9d-765b3e80aee0.png" alt="" style="display:block;margin:0 auto" />

<p>Add all the ports defined below. I've added the description for each port, what it is used for, so you can take a look at it too. Once done, save the rules, and you are good to go.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/5a07569a-c090-470f-a373-2845a94e26ee.png" alt="" style="display:block;margin:0 auto" />

<h4>Creating Worker Nodes</h4>
<p>Now we have one Manager node. We need two worker nodes. The process gonna be the same only except the name of the Instance. Go ahead and create <strong>wrk1</strong> and <strong>wrk2</strong>. I am gonna show <strong>wrk1,</strong> and then you can create <strong>wrk2</strong> on your own. It's pretty simple.</p>
<ol>
<li>Name the instance (wrk1) and select the Ubuntu image.</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/a904b839-a347-4325-b0ec-0e45f9fad67b.png" alt="" style="display:block;margin:0 auto" />

<p>Select the same key pair that we created.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/d06c0d7a-21a3-4b69-bc11-7fe2950fcd03.png" alt="" style="display:block;margin:0 auto" />

<p>Now here comes the most <strong>IMPORTANT</strong> part, so make sure you don't miss it. We need to put all these instances into the <strong>SAME VPC and Subnet</strong> in order for them to work. How will you make sure? Just open the <strong>mgr1 instance (on the right in the screenshot below), go to the Networking tag, and you will see the VPC ID and Subnet ID.</strong></p>
<p>On the worker node (on the left), select the same Subnet ID and VPC ID.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/75c62f65-e8e4-454f-80de-d19e0488bd59.png" alt="" style="display:block;margin:0 auto" />

<p>Once done, launch that instance.</p>
<blockquote>
<p><strong>IMPORTANT:</strong> Make sure you add all the ports like we did for the Manager node.</p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2e0bbd6a-b38e-4c63-ac97-02a8f9451602.png" alt="" style="display:block;margin:0 auto" />

<p>As you can see now, I have all three instances running on my AWS.</p>
<hr />
<h2>SSH into each instance</h2>
<p>Now, let's open these instances in our machine. Open three separate terminals and run below commands</p>
<pre><code class="language-shell">ssh -i ~/Downloads/docker-swarm-test.pem ubuntu@107.21.169.169
</code></pre>
<p>Here, make sure you provide the correct path of the key you downloaded (this is the key which gets downloaded when we created the key-pair). And then specify the <strong>Public IP Address</strong>. Which you will find in the Details tab of the instance</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/daa14961-fd6b-434e-a27b-a4fabc0aa736.png" alt="" style="display:block;margin:0 auto" />

<p>Once done, your terminal will turn into that instance terminal, and you'll see something like this.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/f2b33249-ff1a-498e-8efd-d588e3bfdbe1.png" alt="" style="display:block;margin:0 auto" />

<p>Do this for all three instances, and you will have all three instances running inside your host machine in your terminal.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/79f53448-c010-4190-82a8-d0d24d39462b.png" alt="" style="display:block;margin:0 auto" />

<p>(<strong>Top</strong> - Manager, <strong>Bottom Left</strong> - Worker 1, <strong>Bottom Right</strong> - Worker 2)</p>
<h2>Installing Docker on all 3 instances</h2>
<p>In order to run Docker Swarm, we first need to install Docker inside these instances. To do that run below commands</p>
<pre><code class="language-shell">sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl enable --now docker
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/8a10021b-a465-4299-a661-ce2b389fbc30.png" alt="" style="display:block;margin:0 auto" />

<p>Run those commands in all three terminals, and you will have Docker installed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/a7eed435-7873-4e68-8a18-ec2533dd422d.png" alt="" style="display:block;margin:0 auto" />

<h2>Initializing a new swarm</h2>
<p>Now that we have everything in place, we can go ahead and initialize our Docker swarm. One thing to note about is that, Docker nodes that are not part of swarm are said to be in single-engine mode. Once they're added to a swarm they're automatically switched to <strong>swarm mode</strong>.</p>
<p>Running <code>docker swarm init</code> on a Docker host in <em>single-engine</em> mode will switch that node into swarm mode, create a new swarm, and make the node the first manager of the swarm.</p>
<p>And all the additional nodes can then be joined to the swarm as workers and managers. Joining a Docker host to an exisiting swarm switches them into swarm mode as part of the operation.</p>
<p>Let's run the below command to our manager node to initialize a new swarm.</p>
<pre><code class="language-shell">docker swarm init --advertise-addr &lt;manager-ip-address&gt;
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2c164748-8f50-4d3e-bda8-af28c075b76f.png" alt="" style="display:block;margin:0 auto" />

<p>Let's understand the command:</p>
<p><code>docker swarm init</code> - This tells Docker to initialize a new swarm and make this node the first manager. It also enables swarm mode on the node.</p>
<p><code>--advertise-addr</code> - As the name suggests, this is the swarm API endpoint that will be advertised to other nodes in the swarm. It will be one of the node's IP address, but can be an external load balancer address.</p>
<p><code>--listen-addr</code> - This is the IP address that the node will accept swarm traffic on. If not explicitly set, it defaults to the same value as <code>advertise-addr</code>.</p>
<p>To list the nodes in the swarm run <code>sudo docker node ls</code> command.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/b5576968-b0df-49ad-9d89-a0182d94b187.png" alt="" style="display:block;margin:0 auto" />

<p>As you can see, only the <code>mgr1</code> node is the only node present in the swarm. It's also listed as <strong>Leader</strong>. Now it's time to add the worker nodes to join this swarm too. To do that run below command in manager node</p>
<pre><code class="language-shell">sudo docker swarm join-token worker
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/f00b20ff-a7ca-481f-9304-17ed13235307.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p>If you want another manager to join the swarm, run:</p>
<p><code>sudo docker swarm join-token manager</code></p>
</blockquote>
<p>Now go to the worker nodes (<code>wrk1 and wrk2</code>) and join the swarm using the command you got above:</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/cb93b2af-3550-4020-850f-0795261d2a2f.png" alt="" style="display:block;margin:0 auto" />

<p>That's it. We've just created 3 node swarm with 1 manager and 2 workers. And you can see that by running <code>sudo docker node ls</code> command into the manager node. Nodes with nothing in the Manager Status are <strong>workers.</strong></p>
<p>Also if you notice the asterisk (*) in front of the node ID, it says which node you are logged on to and executing commands from.</p>
<h2>Swarm manager high availability</h2>
<p>You must be asking, why we added managers and workers, and how they work together, and what's the point of all these?</p>
<p>So in real worlds, it can happen that sometimes one or more nodes can fail, but if you are using Swarm, the survivors will keep the swarm running without interrupting anything.</p>
<p>Right now, we have only one manager, but if you have more than one managers, only one of them is active at any given moment. This active manager is called the "<strong>Leader</strong>". And the leader is the only one that will ever issue live commands against the swarm.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/66433f9b-9b47-424c-acbb-0ea783641161.png" alt="" style="display:block;margin:0 auto" />

<p>(Diagram from - Docker Deep Dive book by Nigel Poulton)</p>
<h2>Swarm Services</h2>
<p>A <strong>service</strong> in Docker Swarm is a way to run and manage containers across a cluster of machines. It is a feature that only works when Docker is running in <strong>swarm mode</strong>. A service lets you define how your application should run, and the swarm makes sure that state is always maintained</p>
<p>With services, you can set many of the same options you normally use for containers. For example, you can give the service a name, choose which image to use, map ports, and connect it to networks. But services also add extra features that are useful for modern cloud applications.</p>
<p>You can create services by running <code>docker service create</code> command</p>
<pre><code class="language-shell">docker service create --name web -p 8080:8080 --replica 5 dhruvnakum/web
</code></pre>
<p>For example, a command above create a service named <strong>web</strong>, map port <strong>8080</strong>, and run <strong>5 replicas</strong> using a specific image. After the command runs, the manager node decides where those containers should run in the cluster. Each node that receives a task downloads the image and starts a container.</p>
<p>Swarm also constantly watches all services. It runs a background process that checks if the <strong>actual state</strong> matches the <strong>desired state</strong>. If everything matches, nothing changes. But if something goes wrong, the swarm fixes it automatically.</p>
<p>For example, if one of the machines running a container fails, the number of running containers might drop from <strong>5 to 4</strong>. Swarm will notice this and automatically start another container on a different node to bring the total back to <strong>5</strong>. This is called <strong>self-healing</strong>, and it helps keep applications running even when failures happen.</p>
<p>You can see all services in the swarm using the command</p>
<pre><code class="language-shell">docker service ls
</code></pre>
<p>If you want to see the containers that belong to a specific service, you can use</p>
<pre><code class="language-shell">docker service ps
</code></pre>
<p>Another useful feature is <strong>scaling</strong>. If your application gets more traffic, you can increase the number of running containers. For example, if traffic doubles, you can scale the service from <strong>5 containers to 10</strong> using the command <code>docker service scale</code></p>
<p>Example:</p>
<pre><code class="language-shell">docker service scale web=10
</code></pre>
<pre><code class="language-shell">web scaled to 10
overall progress: 10 out of 10 tasks
1/10: running
2/10: running
3/10: running
4/10: running
5/10: running
6/10: running
7/10: running
8/10: running
9/10: running
10/10: running
verify: Service converged
</code></pre>
<p>When scaling happens, Docker tries to spread the containers evenly across the nodes in the cluster. This helps distribute the workload.</p>
<p>If traffic goes down again, you can scale the service back to a smaller number of containers. For example, you can reduce it from <strong>10 back to 5</strong>.</p>
<pre><code class="language-shell">docker service scale web=5
</code></pre>
<pre><code class="language-shell">web scaled to 5
overall progress: 5 out of 5 tasks
1/5: running
2/5: running
3/5: running
4/5: running
5/5: running
verify: Service converged
</code></pre>
<p>If you no longer need the service, you can remove it using the command <code>docker service rm</code>. When you do this, the service and all of its running containers will be deleted from the swarm.</p>
<pre><code class="language-shell">docker service rm web
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>Phew!! That was a lot, right? But I hope the practical implementation, with screenshots and everything, helped you get the idea of how swarm works.</p>
<p>Docker Swarm is Docker's native technology for managing clusters of Docker nodes and deploying and managing cloud-native apps.</p>
<p>It's similar to Kubernetes. So if you understood this right now. Understanding Kubernetes will become easier for you.</p>
<p>That's it. I hope you learned something from this. Just want to say this, understanding this only won't make you understand everything until you try it on your own. So make sure you practise this.</p>
<p>See you in the next one, until then....peace</p>
<p><a class="embed-card" href="https://giphy.com/gifs/fallontonight-jimmy-fallon-peace-out-tonightshow-2nlbKhgnvAK3sR8ffw?utm_source=iframe&amp;utm_medium=embed&amp;utm_campaign=Embeds&amp;utm_term=https%3A%2F%2Fdhruvnakum.xyz%2F">https://giphy.com/gifs/fallontonight-jimmy-fallon-peace-out-tonightshow-2nlbKhgnvAK3sR8ffw?utm_source=iframe&amp;utm_medium=embed&amp;utm_campaign=Embeds&amp;utm_term=https%3A%2F%2Fdhruvnakum.xyz%2F</a></p>]]></content:encoded></item><item><title><![CDATA[Diving into Docker (Part 6): Docker Networking]]></title><description><![CDATA[Finally, here comes the interesting blog of the Diving into Docker series. I've learned so much from the book (Docker Deep Dive - Nigel Poulton) about networking. It's gonna be so much fun to know how]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-6-docker-networking</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-6-docker-networking</guid><category><![CDATA[Docker]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[containers]]></category><category><![CDATA[networking]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Sun, 15 Mar 2026 21:59:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/b7f57c83-d582-4330-9864-910ef7cec81f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Finally, here comes the interesting blog of the Diving into Docker series. I've learned so much from the book (Docker Deep Dive - Nigel Poulton) about networking. It's gonna be so much fun to know how Docker connects everything internally. So without further ado, let's get started.</p>
<hr />
<p>When people hear Networking, it often sounds complex and scary. But the core ideas are actually simple once you break them down. Let's tackle down and understand the Docker Networking. I will try my best to simplify it, so let's get started.</p>
<p>Docker networking is divided into 3 main parts</p>
<ol>
<li><p><strong>CNM (Container Network Model)</strong> – the design or the plan, you can say</p>
</li>
<li><p><strong>libnetwork</strong> – the implementation or the code that follows the plan</p>
</li>
<li><p><strong>Drivers</strong> – the actual network types (bridge, overlay, macvlan, etc.)</p>
</li>
</ol>
<p>A simple way to remember this is:</p>
<ul>
<li><p><strong>CNM</strong> is like the blueprint of a house</p>
</li>
<li><p><strong>libnetwork</strong> is like the construction team that follows the blueprint</p>
</li>
<li><p><strong>Drivers</strong> are like the different types of houses you can build (apartment, villa, etc.)</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/70a94c05-f526-4033-8955-a1616d8cf90e.png" alt="" style="display:block;margin:0 auto" />

<p>Let’s go step by step and understand these in detail, and make it feel clear.</p>
<hr />
<h2>Part 1: CNM (Container Network Model)</h2>
<p>CNM is not software you install. It’s a design document. Docker created CNM to define how container networking should be structured.</p>
<p>CNM says Docker networking is built using 3 building blocks</p>
<ul>
<li><p>Sandbox</p>
</li>
<li><p>Endpoint</p>
</li>
<li><p>Network</p>
</li>
</ul>
<p>If you understand these three, you understand the base of Docker networking.</p>
<hr />
<h2>1) Sandbox</h2>
<p>A sandbox is an isolated networking environment for a container. That sentence sounds heavy, but here’s what it really means:</p>
<p>Every container gets its own private networking setup, including:</p>
<ul>
<li><p>its own <strong>IP address</strong></p>
</li>
<li><p>its own network interfaces like <strong>eth0</strong> inside the container</p>
</li>
<li><p>its own <strong>routing table</strong> and rules about where traffic should go</p>
</li>
<li><p>its own <strong>DNS</strong> settings</p>
</li>
<li><p>its own <strong>ports</strong></p>
</li>
</ul>
<p>So the sandbox is basically, everything networking related that belongs only to that container.</p>
<p>Think of it like this</p>
<ul>
<li><p>Each container lives in its own room</p>
</li>
<li><p>That room has its own Wi‑Fi setup, its own address, and its own rules</p>
</li>
<li><p>Even if two containers are on the same machine, their “rooms” are still separate</p>
</li>
</ul>
<p>On Linux, Docker achieves this separation using something called <strong>network namespaces</strong>. You don’t have to memorize that right now, just remember the outcome which is, containers behave like separate computers from a networking point of view.</p>
<blockquote>
<p>The important thing to remember here is, for example, even when Container A and Container B run on the same Docker host, their networking is still isolated because each has its own sandbox.</p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/3c9c07b2-e443-484e-aff7-d961d2bdf511.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>2) Endpoint</h2>
<p>Your laptop can connect to Wi‑Fi because it has a network card. Containers don’t have physical network cards. So Docker creates a <strong>virtual network interface</strong> for them. CNM calls this an <strong>endpoint</strong>.</p>
<p>An endpoint’s job is simple, which is to connect a container’s sandbox to a network.</p>
<p>There are two rules that make endpoints easy to understand</p>
<ol>
<li><p>One endpoint connects to exactly one network.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/6bf8d129-e091-48ee-9665-0b13dc0d6a99.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li>If a container needs to join two networks, it needs two endpoints.</li>
</ol>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/8a2a9d19-fde5-481d-9bd1-314c391830eb.png" alt="" style="display:block;margin:0 auto" />

<p>For Example, If a container must talk to both Network A and Network B, Docker gives it</p>
<ul>
<li><p>Endpoint 1 → Network A</p>
</li>
<li><p>Endpoint 2 → Network B</p>
</li>
</ul>
<p>That’s how one container can be part of multiple networks at the same time.</p>
<hr />
<h2>3) Network</h2>
<p>In Docker, a network is like a virtual switch. It groups endpoints. If two containers connect to the same Docker network, they can usually talk to each other.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/96a035c1-51ba-4eb0-861f-5fb1bc91edec.png" alt="" style="display:block;margin:0 auto" />

<p>If they are not on the same network, they can’t talk to each other by default (unless you set up routing manually).</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/edaed8b0-ddfb-46f5-83c5-72b48663cbf2.png" alt="" style="display:block;margin:0 auto" />

<p>A very simple analogy is that a Docker network is like a WhatsApp group. People inside the same group can message each other. If you’re not in the group, you can’t message the group members.</p>
<p>Same idea with containers: same network = communication is possible.</p>
<hr />
<h2>Part 2: libnetwork</h2>
<p>So far, CNM is just a design. It describes what should exist: sandboxes, endpoints, networks. But Docker needs real code that actually creates and manages these things.</p>
<p>That code is called <strong>libnetwork</strong>.</p>
<p>So, CNM says what should exist, <strong>libnetwork</strong> actually creates it and manages it.</p>
<p>Whenever you run commands like:</p>
<ul>
<li><p><code>docker network create</code></p>
</li>
<li><p><code>docker run</code></p>
</li>
<li><p><code>docker network connect</code></p>
</li>
</ul>
<p>Docker Engine uses <strong>libnetwork</strong> behind the scenes. You can think of libnetwork as Docker’s network manager.</p>
<hr />
<h2>Why Docker separated networking from the daemon?</h2>
<p>Early on, a lot of Docker networking code lived inside the Docker daemon <code>dockerd</code>. But over time networking became bigger and more complicated:</p>
<ul>
<li><p>multiple network types (bridge, overlay, macvlan…)</p>
</li>
<li><p>DNS and service discovery features</p>
</li>
<li><p>load balancing</p>
</li>
<li><p>multi-host networking</p>
</li>
</ul>
<p>The daemon started becoming too large and messy. That’s why Docker engineers moved networking into a separate library called <strong>libnetwork</strong>.</p>
<p>This was good because networking could improve without constantly modifying the main daemon, and the design became more modular (cleaner separation), as well as other projects could reuse the networking library</p>
<p>So when someone says networking was ripped out of the daemon and refactored into libnetwork, they mean it was separated into its own component.</p>
<hr />
<h2>Control plane vs Data plane</h2>
<p>These two terms show up a lot in networking. Here’s what it means.</p>
<h3>Control plane (libnetwork)</h3>
<p>The control plane is responsible for deciding how the network should behave and setting up the rules. It does not move packets itself. Instead, it programs the system so packets know where to go. In Docker networking, the control plane is mainly handled by <strong>libnetwork</strong>.</p>
<p>For Example, when you run <code>docker network create mynet</code>: The <strong>control plane performs multiple tasks</strong>.</p>
<h4>1. Create a Network Object</h4>
<p>Docker stores metadata like:</p>
<pre><code class="language-plaintext">Network Name: mynet
Driver: bridge
Subnet: 172.18.0.0/16
Gateway: 172.18.0.1
</code></pre>
<p>This is stored in Docker's internal database.</p>
<h4>2. IP Address Management (IPAM)</h4>
<p>Docker assigns a subnet to the network.</p>
<p>Example:</p>
<pre><code class="language-plaintext">Subnet: 172.18.0.0/16
Gateway: 172.18.0.1
</code></pre>
<p>Later, when containers join the network:</p>
<pre><code class="language-plaintext">Container A → 172.18.0.2
Container B → 172.18.0.3
</code></pre>
<p>IP allocation is controlled by the IPAM system in the control plane.</p>
<h4>3. Select Network Driver</h4>
<p>Docker supports different drivers:</p>
<ul>
<li><p>bridge</p>
</li>
<li><p>overlay</p>
</li>
<li><p>macvlan</p>
</li>
<li><p>host</p>
</li>
<li><p>none</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="language-plaintext">Driver = bridge
</code></pre>
<p>The control plane decides which driver will implement the network.</p>
<h4>4. Maintain Network State</h4>
<p>Control plane tracks:</p>
<ul>
<li><p>which containers belong to the network</p>
</li>
<li><p>assigned IPs</p>
</li>
<li><p>driver configuration</p>
</li>
<li><p>DNS entries</p>
</li>
</ul>
<p>Example state:</p>
<pre><code class="language-plaintext">Network: mynet
Containers:
   web -&gt; 172.18.0.2
   db  -&gt; 172.18.0.3
</code></pre>
<h4>5. Configure System Networking</h4>
<p>The control plane tells Linux:</p>
<ul>
<li><p>create bridges</p>
</li>
<li><p>configure routes</p>
</li>
<li><p>configure iptables rules</p>
</li>
</ul>
<p>But it doesn't move packets itself. Instead, it programs the data plane.</p>
<h3>Data plane (driver)</h3>
<p>Data plane means where the real packets move.</p>
<p>Imagine two containers:</p>
<pre><code class="language-plaintext">Container A
172.18.0.2

Container B
172.18.0.3
</code></pre>
<p>They are connected to:</p>
<pre><code class="language-plaintext">docker0 bridge
</code></pre>
<p>now the network structure is like this</p>
<pre><code class="language-plaintext">Container A
   |
 vethA
   |
 docker0 bridge
   |
 vethB
   |
Container B
</code></pre>
<p>Now when A sends a packet to B:</p>
<pre><code class="language-plaintext">ping 172.18.0.3
</code></pre>
<p>The data plane handles the packet movement.</p>
<hr />
<h2>Implementation</h2>
<p>Let’s walk through a simple example:</p>
<h3>Step 1: Create a bridge network</h3>
<p>You run:</p>
<p><code>docker network create -d bridge mynet</code></p>
<p>Docker Engine receives the command. It asks <code>libnetwork</code> to create a new network object. libnetwork stores, name=mynet, driver=bridge, settings, IP ranges, etc. And then it calls the bridge driver and says build the real network for this.</p>
<p>The bridge driver then sets up Linux-level things like:</p>
<ul>
<li><p>a Linux bridge device</p>
</li>
<li><p>NAT / iptables rules</p>
</li>
<li><p>isolation rules</p>
</li>
</ul>
<h3>Step 2: Run a container on that network</h3>
<p>You run:</p>
<p><code>docker run --network mynet nginx</code></p>
<p>In this case, Docker asks libnetwork to attach this container to “<strong>mynet</strong>”. So what <code>libnetwork</code> will do is create, a sandbox which is a container’s private network environment and an endpoint.</p>
<p>Then libnetwork connects the endpoint to the network and assigns IP + DNS settings. And finally asks the bridge driver that “connect this endpoint to the bridge”</p>
<p>So a very clean way to remember:</p>
<ul>
<li><p>libnetwork organizes and manages</p>
</li>
<li><p>the driver does the real network wiring</p>
</li>
</ul>
<hr />
<h2>Single-host Bridge Networks</h2>
<p>The simplest Docker network type is the single-host bridge network. The name itself tells you the meaning of it. <strong>Single-host</strong> works only on one Docker machine. <strong>Bridge</strong> behaves like a Layer 2 switch.</p>
<p>Every Docker host gets a default bridge network. On Linux it’s called <code>bridge.</code> On Windows it’s called <code>nat.</code></p>
<blockquote>
<p>If you don’t specify a network, containers join this default one</p>
</blockquote>
<p>On Linux, this default <code>bridge</code> network is backed by a real Linux bridge called <code>docker0</code>.</p>
<h3>Creating your own bridge network</h3>
<p>Run the command below to create your own bridge network.</p>
<pre><code class="language-plaintext">docker network create -d bridge localnet
</code></pre>
<p>Then run a container attached to it. For example we have two container <code>c1</code> and <code>c2</code>.</p>
<ul>
<li>run <code>c1</code> on <code>localnet</code></li>
</ul>
<pre><code class="language-plaintext">docker container run -d --name c1 \
--network localnet \
alpine sleep 1d
</code></pre>
<ul>
<li>run <code>c2</code> on <code>localnet</code></li>
</ul>
<pre><code class="language-plaintext">docker container run -d --name c2 \
--network localnet \
ubuntu:latest
</code></pre>
<p>Now <code>c2</code> can reach <code>c1</code>, and very importantly, it can resolve it by name, not just IP.</p>
<p>That leads to an important concept: Service discovery.</p>
<hr />
<h2>Service discovery</h2>
<p>Container IP addresses are often not stable. For example, containers restart and may get a new IP, or scaling up/down creates new containers with new IPs.</p>
<p>So you don’t want your app to hardcode IP addresses.</p>
<p>Instead, you want to say: “talk to db”, “talk to api”, “talk to redis”</p>
<p><strong>That is service discovery, automatic mapping from name → IP.</strong></p>
<p>Docker supports this on the same network using an internal DNS system:</p>
<p>Docker runs an internal DNS server that knows container names and IPs, and containers have a local DNS resolver that forwards requests to Docker’s DNS</p>
<p>So if you run <code>ping c1</code> from inside <code>c2</code>, Docker DNS helps <code>c2</code> translate “c1” into the correct IP.</p>
<blockquote>
<p>This name-based discovery works only within the same Docker network. If two containers aren’t on the same network, Docker DNS won’t resolve them by name for each other.</p>
</blockquote>
<hr />
<h2>Port mapping</h2>
<p>Containers on a bridge network are mainly meant to talk to each other inside the same host/network. But what if you want a browser, something outside Docker, to reach a container web server? That’s where <strong>port mapping</strong> comes in.</p>
<p>For example, you have seen this <code>--publish 5000:80</code> In a command, we write when we run the container. What does that mean?</p>
<p>It simply means that container listens on port 80 and Docker host opens port 5000</p>
<blockquote>
<p>your machine : docker container (5000:80)</p>
</blockquote>
<p>So the outside world talks to the Docker host, and Docker forwards the traffic to the container. This is extremely common for local development.</p>
<hr />
<h2>Multi-host networking</h2>
<p>Bridge networks are great when everything is on one machine. But real systems often run across multiple machines. For example, Host 1 runs some containers. Host 2 runs other containers, and you want containers across hosts to talk like they are on one shared network</p>
<p>By default, containers on different hosts are like they’re in different houses, they’re not on the same local network.</p>
<p>An <strong>overlay network</strong> solves this by creating a virtual network that spans multiple Docker hosts.</p>
<h3>Overlay network</h3>
<p>An overlay network is a virtual network built on top of the real network.</p>
<p>For example, you can consider like this:</p>
<ul>
<li><p>real network = normal roads</p>
</li>
<li><p>overlay network = secret tunnels built on top of those roads</p>
</li>
</ul>
<p>Containers use the tunnels so that, even across different machines, they behave like they’re on the same LAN.</p>
<h3>How overlay “tunneling” works</h3>
<p>When Container A on Host 1 sends data to Container B on Host 2:</p>
<ul>
<li><p><strong>A</strong> sends a normal packet, it thinks <strong>B</strong> is nearby.</p>
</li>
<li><p>Docker on Host 1 wraps that packet inside another packet like putting a letter in an envelope</p>
</li>
<li><p>the outer packet travels over the real network to Host 2</p>
</li>
<li><p>Docker on Host 2 unwraps it and delivers the original packet to B</p>
</li>
</ul>
<p>Docker has a built-in overlay driver, so you can create an overlay network like:</p>
<pre><code class="language-plaintext">docker network create -d overlay mynet
</code></pre>
<p>Usually this is used with Swarm or other orchestrators</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/38d9ebf5-2cfe-489a-aa41-99b0ba95b8ca.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>MACVLAN: making containers look like real devices on your LAN</h2>
<p>Overlay is about connecting containers across hosts inside a Docker-managed virtual network. Macvlan is a different goal.</p>
<p>Macvlan is used when you want containers to join the real physical network directly.</p>
<p>In other words, instead of hiding containers behind the host like bridge / NAT often does, <strong>macvlan</strong> makes each container appear like a real machine on your network.</p>
<p>With macvlan, each container gets its own MAC address, its own IP address from your real LAN subnet</p>
<p>So your switch/router sees the container as it sees: your laptop, a server, a VM, and now… the container</p>
<p>macvlan often requires the host network card to be in promiscuous mode. Promiscuous mode is sometimes blocked in corporate networks or cloud providers</p>
<p>So, macvlan is commonly a good fit in controlled environments like data centers.</p>
<hr />
<h2>Overlay vs Macvlan</h2>
<p>Overlay:</p>
<ul>
<li><p>Best for container-to-container communication across multiple Docker hosts.</p>
</li>
<li><p>Containers feel like they are on one shared Docker network.</p>
</li>
<li><p>Common in clusters, Swarm or microservices</p>
</li>
</ul>
<p>Macvlan:</p>
<ul>
<li><p>Best when containers must be first-class citizens on the physical network</p>
</li>
<li><p>Containers get real LAN IPs and MACs</p>
</li>
<li><p>Common when containers must talk to physical servers directly and be reachable from outside without port mapping</p>
</li>
</ul>
<hr />
<h2>Swarm publishing: Ingress mode vs Host mode</h2>
<p>In Swarm, you usually deploy services and not individual containers. A service can have replicas running on different nodes. And to allow outside users to access a service, you publish a port.</p>
<p>For example,</p>
<ul>
<li><p>published port (outside) = 5000</p>
</li>
<li><p>target port (inside container) = 80</p>
</li>
</ul>
<p>Swarm supports two publishing modes:</p>
<h3>1) Ingress mode (default)</h3>
<ul>
<li><p>Any node can accept traffic, even if it’s not running the container. And the cluster routes it internally to the right node.</p>
</li>
<li><p>Ingress mode is the default. This means any time you publish a service with -p or --publish it will default to ingress mode.</p>
</li>
<li><p>To publish a service in host mode you need to use the long format of the <code>--publish</code> flag and add <code>mode=host</code>. Let’s see an example using host mode.</p>
</li>
</ul>
<pre><code class="language-plaintext">docker service create -d --name c1 \
--publish published=5000,target=80,mode=host \
nginx
</code></pre>
<h3>2) Host mode</h3>
<ul>
<li>In this case, only nodes that are actually running the service accept traffic on that port.</li>
</ul>
<p>In practice, people often talk about routing mesh and load balancing here. If multiple replicas exist, Swarm can spread incoming requests across them.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/a734834b-8972-4f61-ad21-a8ef81599b3d.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>Conclusion</h2>
<ul>
<li><p>So in summary, Docker networking boils down to three things.</p>
<ul>
<li><p><strong>CNM</strong> defines the model - sandbox, endpoint, network.</p>
</li>
<li><p><strong>libnetwork</strong> is the <strong>manager</strong> that creates and connects those pieces, and drivers - bridge/overlay/macvlan, do the real packet-moving work.</p>
</li>
<li><p><strong>Bridge</strong> is for containers on one host, overlay connects containers across hosts like one network, and macvlan puts containers directly onto the physical LAN with their own MAC/IP.</p>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Diving into Docker (Part 5): Deploying apps with `docker-compose` ]]></title><description><![CDATA[In the previous blog...
We saw how we can containerize our application and push it to the Docker Hub registry for anyone to use.
In real world, applications are not that simple, right? There are loads]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-5-deploying-apps-with-docker-compose</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-5-deploying-apps-with-docker-compose</guid><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Sat, 14 Mar 2026 18:27:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/289c0df5-d354-42dc-acef-630d60c8794a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>In the previous blog...</h2>
<p>We saw how we can containerize our application and push it to the Docker Hub registry for anyone to use.</p>
<p>In real world, applications are not that simple, right? There are loads of things like, web server, database, cache, some background worker, etc. And things get complicated quickly. If we try to manage this using <code>docker run</code> command and custom scripts then things become messy and hard to maintain.</p>
<p>This is exactly where <strong>Docker Compose</strong> helps. Docker Compose lets you describe your entire multi-container application in one simple configuration file, and then deploy everything with a single command. Instead of remembering a dozen commands, you maintain one declarative file. Once the app is running, Compose also gives you a small set of commands to manage the whole app’s lifecycle, like start, stop, restart, view status, and tear it down cleanly. Because the configuration is just a text file, you can also store it in Git and treat it like normal code.</p>
<p>Docker Compose works across platforms, and if you use Docker Desktop on Mac, Compose is typically installed automatically. You can quickly verify it by checking the version with <code>docker-compose --version</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/8ac6bdef-6e34-44c0-8435-be2663d4719f.png" alt="" style="display:block;margin:0 auto" />

<h2>Understanding Compose Files (YAML)</h2>
<p>Docker Compose uses a YAML file to define a multi-service application. YAML is popular because it’s human-readable and clean for configuration. Technically, YAML is a superset-like format that can represent the same structures as JSON, and Compose also supports JSON, but YAML is the standard and most common format you’ll see in real projects.</p>
<p>By default, Compose looks for a file named <code>docker-compose.yml</code>. If you want to use a different name, for example, a production-specific file, you can pass the filename using the <code>-f</code> flag when you run Compose.</p>
<p>To make this more understandable, imagine a small app built with three services:</p>
<ul>
<li><p>backend</p>
</li>
<li><p>frontend</p>
</li>
<li><p>db</p>
</li>
</ul>
<p>Compose lets you define all the services together so they can be started and managed as one unit.</p>
<h2>What’s Inside a <code>docker-compose.yml</code></h2>
<p>Just look at the below docker-compose file.</p>
<pre><code class="language-shell">version: "3.8"
services:
  web-fe:
   ...
  redis:
   ...
networks:
  counter-net:

volumes:
  counter-volume:
</code></pre>
<p>A Compose file is structured into top-level sections (keys). The file includes mostly these four important top-level keys:</p>
<ol>
<li><p><code>version</code></p>
</li>
<li><p><code>services</code></p>
</li>
<li><p><code>networks</code></p>
</li>
<li><p><code>volumes</code></p>
</li>
</ol>
<p>Other top-level keys also exist (like <code>secrets</code> and <code>configs</code>), but these four are the core ones you’ll see often.</p>
<h3>1) <code>version</code>: Compose file format version</h3>
<p>The <code>version</code> key is required in this style of Compose file and appears at the top. It defines the version of the Compose file format, you can think of it like the schema/API version for the YAML format. A common mistake is assuming this refers to your Docker Engine version or the Docker Compose binary version it does not. It only describes the format rules for the YAML file itself.</p>
<p>In your example, the Compose file uses version <code>3.8</code>, which is a widely used format.</p>
<h3>2) <code>services</code>: The containers that make up your app</h3>
<p>The <code>services</code> section is the heart of Compose. This is where you define each microservice that will run as a container. In the example, there are two services: <code>web-fe</code> and <code>redis</code>.</p>
<p>A really important detail is that Compose uses these service names when it generates container names. So if you define services named <code>web-fe</code> and <code>redis</code>, the containers created will include those names (often combined with the project name, like <code>counter-app_web-fe_1</code>). This naming becomes useful when you’re troubleshooting, checking logs, or inspecting containers later.</p>
<h3>3) <code>networks</code>: How containers talk to each other</h3>
<p>The <code>networks</code> section tells Docker what networks to create. By default, Compose typically creates <strong>bridge networks</strong>, which are <strong>single-host networks</strong>. That means the network connects containers running on the same Docker host. If you need more advanced networking, Compose can reference other drivers, but the default bridge model is perfect for local development and many single-host deployments.</p>
<blockquote>
<p>We have the whole dedicated Docker Networking blog upcoming, so stay tuned</p>
</blockquote>
<p>In the example, a network named <code>counter-net</code> is defined. Both the service attach to this network, which means they can talk to each other using service names as DNS names.</p>
<h3>4) <code>volumes</code>: Persistent data storage</h3>
<p>The <code>volumes</code> section defines Docker volumes that should exist for the application. Volumes are used when you want data to survive container restarts and container deletion. This is especially important for databases, but it’s also helpful for development workflows where you want to persist files, cached dependencies, or app state.</p>
<p>In the example, a volume called <code>counter-vol</code> is defined and mounted into the <code>web-fe</code> container. This means some directory inside the container maps to a real persistent storage location managed by Docker.</p>
<h2>Breaking Down the Example Services</h2>
<pre><code class="language-shell">version: "3.8"
services:
  web-fe:
    build: .
    command: python app.py
    ports:
      - target: 5000
        published: 5000
    networks:
      - counter-net
    volumes:
      - type: volume
        source: counter-vol
        target: /code
  redis:
    image: "redis:alpine"
    networks:
      counter-net:

networks:
  counter-net:

volumes:
  counter-vol:
</code></pre>
<h3>The <code>web-fe</code> service</h3>
<p>The <code>web-fe</code> service is a custom application container. Instead of pulling a prebuilt image from Docker Hub, it uses <code>build: .</code>. That tells Docker: Build an image from the Dockerfile in the current directory. This is a very common development pattern because you keep the application code and Dockerfile together in one repo.</p>
<p>Next, the service defines a command like <code>python app.py</code>. This tells the container what process to run when it starts. In this case, the main process is a Python program called <code>app.py</code> your Flask web app.</p>
<p>It also defines <code>ports</code>, mapping port 5000 inside the container to port 5000 on the host machine. This is what makes the app accessible from your browser. Without a port mapping, the service might run fine but would be isolated inside Docker networking and not reachable directly from your host.</p>
<p>The service attaches to the <code>counter-net</code> network. This is critical because it allows <code>web-fe</code> to communicate with <code>redis</code> over an isolated internal network and it also keeps the service topology tidy instead of throwing everything onto the default network.</p>
<p>Finally, the service mounts a volume. The Compose file mounts <code>counter-vol</code> into <code>/code</code> inside the container. This means files written into <code>/code</code> in the container are actually stored in a Docker managed volume, so they persist beyond the lifecycle of that one container instance.</p>
<p>Putting it all together, Compose deploys one container for <code>web-fe</code>, built from your local Dockerfile, running <code>app.py</code>, exposed on port 5000, connected to the app network, and using persistent storage for the mounted path.</p>
<h3>The <code>redis</code> service</h3>
<p>The <code>redis</code> service is simpler because it uses an existing image: <code>redis:alpine</code>. This tells Docker to pull the Redis image from Docker Hub if it’s not already present locally.</p>
<p>It also attaches to the same <code>counter-net</code> network, so the web service can talk to it. There’s no need to publish Redis ports to the host unless you specifically want to connect to Redis from outside Docker. Many apps keep Redis internal, accessible only to other containers.</p>
<h2>Deploying a Multi-Container App with One Command</h2>
<p>Let's clone an example app repo and start it using Compose.</p>
<ul>
<li><p><code>git clone &lt;</code><a href="https://github.com/red-star25/docker_tutorial_compose_example">https://github.com/red-star25/docker_tutorial_compose_example</a>&gt;</p>
</li>
<li><p><code>docker-compose up &amp;</code></p>
</li>
</ul>
<p>The <code>docker-compose up</code> command is the standard way to bring up an app. When you run it, Compose does several things for you automatically:</p>
<ol>
<li><p>Builds images that require building (like the <code>web-fe</code> service)</p>
</li>
<li><p>Pulls images that need downloading (like <code>redis:alpine</code>)</p>
</li>
<li><p>Creates required networks <code>counter-net</code>)</p>
</li>
<li><p>Creates required volumes ( <code>counter-volume</code>)</p>
</li>
<li><p>Starts containers in the correct configuration</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/bb36f02e-2cc5-4615-b0d6-7f343293f739.png" alt="" style="display:block;margin:0 auto" />

<p>By default, <code>docker-compose up</code> expects the Compose file to be named <code>docker-compose.yml</code>. If your file is named something else, you must pass it with <code>-f</code>. For example, if your file is <code>something-else.yml</code>, you would run <code>docker-compose -f something-else.yml up</code>.</p>
<p>Many people also start apps in “detached mode” using <code>-d</code>, which runs containers in the background and returns your terminal immediately. So instead of using <code>&amp;</code>, you can run <code>docker-compose up -d</code>. Both approaches give you your terminal back, but <code>-d</code> is the standard Compose way.</p>
<p>After the app starts, you can confirm what happened by listing images, containers, and networks. You’ll notice a new image for the web app (created from your Dockerfile) and a container for each service.</p>
<p><code>docker container ls</code></p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/3d095bac-16d5-455b-92d7-e8ac6ceb5365.png" alt="" style="display:block;margin:0 auto" />

<p><code>docker image ls</code></p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/a97f2b15-7324-4ba2-af8a-a36a4562cbd1.png" alt="" style="display:block;margin:0 auto" />

<p>At this point, you’ve successfully deployed a multi-container app using Compose.</p>
<h2>Managing the App Lifecycle with Compose</h2>
<p>Once the app is running, Compose becomes your control panel.</p>
<h3>Stopping and removing: <code>docker-compose down</code></h3>
<p>If you want to stop the app and remove the containers and network it created, you use <code>docker-compose down</code>. This is like the tear down the environment command. It shuts down the services and removes the containers (and usually the default network created for the app).</p>
<p><code>docker-compose down</code></p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/b321daee-45fd-4ee6-99d9-7eb013288645.png" alt="" style="display:block;margin:0 auto" />

<p>A key detail from here is that volumes are not deleted by default when you run <code>down</code>. This is intentional. Volumes are meant to store persistent data, so Docker treats them as long-lived resources. That means if your app wrote data to a volume, the data will still be there the next time you bring the app up.</p>
<p>Also, images you built or pulled remain on the system. This is another reason redeployments become faster because Docker doesn’t need to download or rebuild everything again unless something changed.</p>
<h3>Bringing it back quickly: <code>docker-compose up -d</code></h3>
<p>If you run <code>docker-compose up -d</code> again after bringing it down, you’ll often see it start faster. The images are already present and the volume still exists, so Compose only needs to recreate containers and the network, then start everything.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/3a2e3d98-d6e4-412c-9918-ee0c377e61c9.png" alt="" style="display:block;margin:0 auto" />

<h3>Checking status: <code>docker-compose ps</code></h3>
<p>To see what containers belong to the Compose app and their status (running/stopped), you use <code>docker-compose ps</code>. This is more convenient than <code>docker container ls</code> because it focuses on the services in the Compose project.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/e2c8e84c-7919-4952-ba56-d83e84c1831c.png" alt="" style="display:block;margin:0 auto" />

<h3>Seeing processes inside containers: <code>docker-compose top</code></h3>
<p>If you want to see which processes are running inside each service container, you can use <code>docker-compose top</code>. This is useful when debugging “Is my app actually running?” situations.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/a86ca499-ec59-49ec-8c09-c451057c4592.png" alt="" style="display:block;margin:0 auto" />

<h3>Stop without deleting resources: <code>docker-compose stop</code></h3>
<p>Sometimes you just want to pause the app without removing containers, networks, and configuration. <code>docker-compose stop</code>stops all containers in the Compose app but keeps them around. You can then confirm their status using <code>docker-compose ps</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/153e816f-e3d9-429f-9ea4-ae12d89d866a.png" alt="" style="display:block;margin:0 auto" />

<h3>Restarting: <code>docker-compose restart</code></h3>
<p>If you’ve stopped the app (or if something is acting strange), <code>docker-compose restart</code> restarts the services. It’s a convenient way to bounce the entire application without destroying and recreating everything.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/87da64f6-8905-490f-8445-2438686f88f1.png" alt="" style="display:block;margin:0 auto" />

<h2>Key Docker Compose Commands</h2>
<p>To wrap everything up, here’s what the common commands mean in simple terms:</p>
<p><code>docker-compose up</code> starts the whole app (building/pulling images, creating networks/volumes, starting containers).</p>
<p><code>docker-compose up -d</code> does the same but runs in the background.</p>
<p><code>docker-compose ps</code> shows the status of the app’s containers.</p>
<p><code>docker-compose top</code> shows the processes running inside each container.</p>
<p><code>docker-compose stop</code> stops the containers but keeps them and their resources.</p>
<p><code>docker-compose restart</code> restarts containers that belong to the app.</p>
<p><code>docker-compose down</code> stops and removes the app’s containers</p>
<p><code>docker-compose rm</code> removes stopped containers</p>
<h2>Final Thoughts</h2>
<p>Docker Compose is powerful because it turns a messy set of manual Docker commands into one clean, version-controlled application definition. It makes it easy to bring up complex multi-service applications on your machine or on a server, and it gives you a consistent way to manage the application over time.</p>
<p>Once you get comfortable reading and writing Compose files especially understanding <code>services</code>, <code>networks</code>, and <code>volumes</code> you’ll find deploying and managing multi-container apps becomes much simpler and far less error-prone.</p>
<p>See you in the next one, until then...</p>
<p><a class="embed-card" href="https://giphy.com/gifs/fallontonight-jimmy-fallon-peace-out-tonightshow-2nlbKhgnvAK3sR8ffw?utm_source=iframe&amp;utm_medium=embed&amp;utm_campaign=Embeds&amp;utm_term=https%3A%2F%2Fdhruvnakum.xyz%2F">https://giphy.com/gifs/fallontonight-jimmy-fallon-peace-out-tonightshow-2nlbKhgnvAK3sR8ffw?utm_source=iframe&amp;utm_medium=embed&amp;utm_campaign=Embeds&amp;utm_term=https%3A%2F%2Fdhruvnakum.xyz%2F</a></p>]]></content:encoded></item><item><title><![CDATA[Diving into Docker (Part 4): Containerizing an app]]></title><description><![CDATA[Docker is all about taking an application and running it inside a container. As we saw in the previous blog, a container is a lightweight package that has your app plus everything it needs to run. Thi]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-4-containerizing-an-app</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-4-containerizing-an-app</guid><category><![CDATA[Docker]]></category><category><![CDATA[containerization]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[software development]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Fri, 13 Mar 2026 22:17:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/7102f925-0c6f-436a-96a0-e3fd60cb44fd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Docker is all about taking an application and running it inside a container. As we saw in the previous blog, a container is a lightweight package that has your app plus everything it needs to run. This makes it much easier to build, ship, and run the same app on different computers without the it works on my machine problem. That's the whole point, right?</p>
<p>When you containerize an app, you are basically preparing it so Docker can turn it into an image, and then run that image as a container.</p>
<h3>What does “containerizing” actually mean?</h3>
<p>Think of containerizing like packing your app into a travel bag:</p>
<ul>
<li><p>Your app code is inside the bag.</p>
</li>
<li><p>Your app dependencies, like Node.js packages, etc, are inside the bag.</p>
</li>
<li><p>The instructions on how to start your app are also inside the bag.</p>
</li>
</ul>
<p>Once the bag is packed, anyone can run it the same way, as long as they have Docker.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/59be4c47-52f6-409d-b26a-3e211e76da4c.png" alt="" style="display:block;margin:0 auto" />

<h3>The usual flow of containerizing an app</h3>
<p>Most Docker container workflows follow the same steps:</p>
<p>First, you start with your <strong>application code</strong> and <strong>whatever it depends on (libraries, packages, config files)</strong>. Next, you write a <strong>Dockerfile</strong>. This Dockerfile is a set of instructions that tells Docker how to build your app into an image.</p>
<p>After that, you run a Docker build command. Docker reads your Dockerfile line by line and creates an image. Once you have an image, you can store it in an image registry (optional, but very common). Finally, you run a container using that image.</p>
<p>So the flow is:</p>
<p>You have code → you create a Dockerfile → you build an image → you push it to a registry (this is optional) → you run a container.</p>
<h3>Example: containerizing a simple single-container app</h3>
<p>Let’s say you want to containerize a small Node.js web app.</p>
<p>You copy the code from GitHub and go into the project folder:</p>
<ul>
<li><a href="https://github.com/red-star25/docker_tutorial_sample_nodejs_app.git">https://github.com/red-star25/docker_tutorial_sample_nodejs_app.git</a> clone this repository</li>
</ul>
<p>Inside that folder, you’ll find the Dockerfile.</p>
<h3>What is a Dockerfile?</h3>
<p>A Dockerfile is the starting point for creating a container image. It describes:</p>
<ul>
<li><p>What base system should your app start from</p>
</li>
<li><p>What software needs to be installed</p>
</li>
<li><p>What files to copy into the image</p>
</li>
<li><p>Which command should run when the container starts</p>
</li>
</ul>
<p>One important detail: the folder that contains your app code and files you want to copy into the image is called the <strong>build context</strong>. Most people keep the Dockerfile at the root of this folder, so it is easy to build.</p>
<p>Also, the name matters: it must be exactly <code>Dockerfile</code> with a capital <strong>D</strong>, and it must be one word.</p>
<h3>Walking through the example Dockerfile</h3>
<p>Here is the Dockerfile from the page, and what each line is doing:</p>
<p>The first line is:</p>
<ul>
<li><code>FROM alpine</code></li>
</ul>
<p>This means: start with Alpine Linux as the base image. Alpine is a very small Linux image, so it’s popular for small containers. Every Dockerfile must start with a <code>FROM</code> instruction because it sets the base layer.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2ffdd6d0-ef01-489a-a352-d635f5133b30.png" alt="" style="display:block;margin:0 auto" />

<p>Then we have:</p>
<ul>
<li><code>LABEL maintainer="dhruv.nakum25@gmail.com"</code></li>
</ul>
<p>A label is metadata. It doesn’t install anything or change files in a big way. It’s just extra information added to the image. Adding a maintainer label is a nice practice because people know who to contact about the image.</p>
<p>Next is:</p>
<ul>
<li><code>RUN apk add --update nodejs nodejs-npm</code></li>
</ul>
<p>This installs Node.js and npm in the image using Alpine’s package manager <code>apk</code>. This step creates a new image layer because it adds software to the image.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/bf94b974-b9f9-4b2e-8dea-54f1a8ded9de.png" alt="" style="display:block;margin:0 auto" />

<p>Then:</p>
<ul>
<li><code>COPY . /src</code></li>
</ul>
<p>This copies everything in your build context (your current folder) into the image at <code>/src</code>. This also creates a new layer, because you are adding files to the image.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2d523308-6758-433c-a18a-bc3cd9974120.png" alt="" style="display:block;margin:0 auto" />

<p>Next:</p>
<ul>
<li><code>WORKDIR /src</code></li>
</ul>
<p>This sets the working directory inside the image. From this point onward, commands run as if <code>/src</code> is the current folder. This is usually metadata, not a layer that adds content.</p>
<p>After that:</p>
<ul>
<li><code>RUN npm install</code></li>
</ul>
<p>This runs npm install inside <code>/src</code> (because of the WORKDIR). It installs dependencies listed in <code>package.json</code>. This creates another new layer because it adds installed packages into the image.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/cd7a8e3e-0243-4806-a09d-1bdb0662517d.png" alt="" style="display:block;margin:0 auto" />

<p>Then:</p>
<ul>
<li><code>EXPOSE 8080</code></li>
</ul>
<p>This tells that the app listens on port 8080 inside the container. This is important for humans and tools, but it’s metadata, not a layer.</p>
<p>Finally:</p>
<ul>
<li><code>ENTRYPOINT ["node", "./app.js"]</code></li>
</ul>
<p>This tells Docker what command should run when the container starts. In this case, it runs the Node app. This is also metadata.</p>
<h3>Building the Docker image</h3>
<p>Once you have the Dockerfile, you build the image using the build command. In this example, the image is called <code>web:latest</code>.</p>
<p>The command is:</p>
<ul>
<li><code>docker image build -t web:latest .</code></li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/705b82d2-a803-453e-ac4f-ab7b995ed9b3.png" alt="" style="display:block;margin:0 auto" />

<p>The dot (<code>.</code>) at the end is very important. It tells Docker use my current folder as the build context.</p>
<p>After the build finishes, you can list images to confirm it exists:</p>
<ul>
<li><code>docker image ls</code></li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/9a06846f-e8de-46a9-8db2-b3d840ed3b36.png" alt="" style="display:block;margin:0 auto" />

<p>You can also inspect the image to see what settings Docker stored from your Dockerfile:</p>
<ul>
<li><code>docker image inspect web:latest</code></li>
</ul>
<p>This is a good way to confirm things like the entry point and the image layers.</p>
<h3>Pushing images to a registry (Docker Hub)</h3>
<p>Pushing is optional, but it’s very useful. If your image is only on your laptop, no one else can pull it easily. If you push it to a registry, you can download and run it from anywhere.</p>
<p>Docker Hub is the most common public registry and is the default place Docker pushes to.</p>
<p>First you login:</p>
<ul>
<li><code>docker login</code></li>
</ul>
<p>Before pushing, you need to tag the image properly. Docker needs three parts:</p>
<ul>
<li><p>Registry (example: <a href="http://docker.io/">docker.io</a> for Docker Hub, even if you don’t write it)</p>
</li>
<li><p>Repository (often includes your username)</p>
</li>
<li><p>Tag (like latest, v1, etc.)</p>
</li>
</ul>
<p>If you try to push <code>web:latest</code> directly, Docker will attempt to push it to a repository named <code>web</code>, which you probably don’t own.</p>
<p>So instead, you tag it with your Docker Hub username (Docker ID). Example from the page:</p>
<ul>
<li><code>docker image tag web:latest dhruvnakum/web:latest</code></li>
</ul>
<p>This does not remove the old tag. It just adds another tag pointing to the same image.</p>
<p>Now you can push:</p>
<ul>
<li><code>docker image push dhruvnakum/web:latest</code></li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/4db401e1-3e91-47fb-9a2c-89bf427bd448.png" alt="" style="display:block;margin:0 auto" />

<p>Once it is pushed, you can pull it later from anywhere.</p>
<h3>Running the container</h3>
<p>After the image is built, you run it as a container.</p>
<p>Example command:</p>
<ul>
<li><code>docker container run -d --name mycontainer -p 80:8080 web:latest</code></li>
</ul>
<p>Let’s break that down simply:</p>
<ul>
<li><p><code>-d</code> means run in the background (detached mode)</p>
</li>
<li><p><code>--name c1</code> gives the container a friendly name</p>
</li>
<li><p><code>-p 80:8080</code> maps port 80 on your computer to port 8080 inside the container</p>
</li>
<li><p><code>web:latest</code> is the image you want to run</p>
</li>
</ul>
<p>So if your app listens on 8080 inside the container, you can visit <code>http://localhost</code> in your browser because port 80 on your machine is connected to port 8080 in the container.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2e870ca3-2346-4c5d-9c8b-7f8cf213ab58.png" alt="" style="display:block;margin:0 auto" />

<h3>A closer look: layers vs metadata</h3>
<p>Docker reads the Dockerfile from top to bottom, one line at a time. Some lines create real filesystem layers, and some lines only create metadata.</p>
<p>In general:</p>
<ul>
<li><p>Instructions like <code>FROM</code>, <code>RUN</code>, and <code>COPY</code> create layers because they add or change files.</p>
</li>
<li><p>Instructions like <code>WORKDIR</code>, <code>EXPOSE</code>, <code>ENV</code>, and <code>ENTRYPOINT</code> usually add metadata instead of creating layers.</p>
</li>
</ul>
<p>If you want to see the image build steps and layers, you can use:</p>
<ul>
<li><code>docker image history web:latest</code></li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/89d7117f-408c-42d0-a033-1cdf8792c6c7.png" alt="" style="display:block;margin:0 auto" />

<p>And to verify the final result including entrypoint and layers, use:</p>
<ul>
<li><code>docker image inspect web:latest</code></li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/bf903fb9-5f50-4b96-9ab8-6af8a7d8d535.png" alt="" style="display:block;margin:0 auto" />

<h3>Why image size matters</h3>
<p>When it comes to Docker images, big is bad.</p>
<p>Smaller images are usually:</p>
<ul>
<li><p>faster to build</p>
</li>
<li><p>faster to push and pull</p>
</li>
<li><p>easier to store</p>
</li>
<li><p>less risky</p>
</li>
</ul>
<p>A common problem is that we install build tools and temporary dependencies, but then we forget to remove them. That makes production images bigger than they need to be.</p>
<p>Multi-stage builds solve this in a clean way. A multi-stage Dockerfile has multiple <code>FROM</code> lines. Each <code>FROM</code> starts a new stage. You can build in one stage, and then copy only the final needed output into the last stage (which stays small and clean).</p>
<h3>Build cache best practices</h3>
<p>Docker tries to speed up builds using cache.</p>
<p>For each Dockerfile instruction, Docker checks if it already has a cached layer for that exact step. If yes, it reuses it, and the build is faster. If no, Docker builds a new layer.</p>
<p>But here’s the key: once the cache is broken at some step, Docker usually has to rebuild everything after that step too.</p>
<p>That’s why ordering your Dockerfile matters a lot.</p>
<p>Also, Docker checks files you copy. Even if the Dockerfile line didn’t change, if the content of files in the folder changed, the checksum will change and Docker will rebuild that layer.</p>
<p>If you ever want to ignore cache completely, you can build with:</p>
<ul>
<li><code>docker image build --no-cache=true -t web:latest .</code></li>
</ul>
<h3>Squashing images</h3>
<p>Sometimes images end up with many layers. Squashing can combine layers into fewer layers.</p>
<p>This can be helpful when you want fewer layers, but it has a downside: squashed images don’t share layers as efficiently. That can increase storage usage and make pushes/pulls bigger in some cases.</p>
<p>If you want to squash during build, you can add <code>--squash</code> to the build command.</p>
<h2>Conclusion</h2>
<p>So we learned that containerizing an app is mainly about writing a good Dockerfile and using it to build a clean image. Once you have an image, you can run it the same way on any Docker host, and you can share it by pushing to a registry. That's it.</p>
<p>Next up, we have <strong>docker-compose.</strong> It's the most fundamental topic for multi-stage builds. And we use it in production. So it's gonna be really fun learning that. But for now, create a simple app, containerize it using Dockerfile, and try it on your own and see if you understood the concept till now. Until then...</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/02925105-deb0-44f1-8495-a0972248855e.png" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[Diving into Docker (Part 3) : Container]]></title><description><![CDATA[In the previous blog...
We learned about Images. What image is, and how it works internally. In this blog, we are gonna dive deep into Containers and learn what they are, how they differ from VMs, the]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-3-container</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-3-container</guid><category><![CDATA[Docker]]></category><category><![CDATA[containers]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Thu, 12 Mar 2026 22:01:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/336026a6-002f-4d3a-9b4e-880fb4157755.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>In the previous blog...</h2>
<p>We learned about Images. What image is, and how it works internally. In this blog, we are gonna dive deep into Containers and learn what they are, how they differ from VMs, their use cases, their lifecycle, and much more. So let's get right into it.</p>
<hr />
<h3>What is a container?</h3>
<p>Containers are one of the main ideas behind Docker. If you understand what a container is and how to run one, most Docker commands will start to make sense.</p>
<p>A <strong>container</strong> is a running copy of an <strong>image</strong>. What does that mean!!?</p>
<p>In the previous blog, we learned about images and saw that an <strong>image</strong> is like a blueprint/class that has everything needed to run an app. And to make use of the class what do we do in programming!!?? Yes, we make objects out of it.</p>
<p>That's what a container is. A <strong>container</strong> is what you get when you start that image. And you can start <strong>many containers from the same image, as you would with a class and an</strong> <strong>object</strong>.</p>
<p>Let's now see the difference between Containers and VMs, because hey, we had VMs earlier, which solved our problems, right? Then why container?</p>
<h3>Containers vs Virtual Machines (VMs)</h3>
<p>Containers and VMs both run on a host machine (your laptop, a server, or a cloud instance). But they work differently.</p>
<h4>How VMs work</h4>
<p>VMs use a <strong>hypervisor</strong>. You might or might not know about a hypervisor, so let me give you the basic idea about it.</p>
<blockquote>
<h4>Hypervisor</h4>
<p>A hypervisor is software that lets you run multiple virtual machines (VMs) on one physical computer. It creates virtual machines, Gives each VM its own CPU, memory and storage. It keeps VMs isolated from each other and shares the physical hardware safely.</p>
<p>So instead of one computer running one OS, you can run: Window, Linux, Another Linux, etc all on the same machine</p>
<p>So each VM has, its own OS and kernel. This is why we say "Hypervisors virtualize hardware."</p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/064e040d-a1af-407b-aaff-1f158975eb3b.png" alt="" style="display:block;margin:0 auto" />

<h4>How do containers work?</h4>
<p>Unlike VMs, containers do not create an OS for every app. It shares the host operating system and also shares its kernel.</p>
<p>What it does is split OS resources into isolated containers, meaning each container has its own filesystem, processes, and network space.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/556498d8-3de0-429b-9836-362495f2e279.png" alt="" style="display:block;margin:0 auto" />

<p>This is why we say, <strong>“Containers virtualize the operating system.”</strong></p>
<p>One downside of containers is that they are less secure by default than VMs, because isolation is not as strong as that of VMs. There are ways to improve security, but they can add complexity.</p>
<hr />
<h2>Running your first container</h2>
<p>Let's now create our first container, and the easiest way to start a container is:</p>
<pre><code class="language-shell">docker container run &lt;image&gt; &lt;app&gt;
</code></pre>
<p>Example:</p>
<pre><code class="language-bash">docker container run -it ubuntu /bin/bash
</code></pre>
<p>What this does:</p>
<ul>
<li><p><code>docker container run</code> creates and starts a new container</p>
</li>
<li><p><code>-it</code> connects your terminal to the container (interactive mode)</p>
</li>
<li><p><code>ubuntu</code> Is the image</p>
</li>
<li><p><code>/bin/bash</code> is the app (a shell) that runs inside the container</p>
</li>
</ul>
<p>Your terminal prompt will change because you are now inside the container.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/d31a7e2b-de25-4884-80f2-18152529fb9b.png" alt="" style="display:block;margin:0 auto" />

<h3>What's happening behind the scenes?</h3>
<p>So when you hit enter after running the above command, the Docker client will send this command to the API server running on the Docker Daemon. Docker Daemon will search for the Docker host's local image repository to see if it already has a copy of the requested image. If it finds the image, it will pull it locally, otherwise, it will go to the Docker hub (image repository) and see if it can find it there.</p>
<p>Once the image is pulled, Docker Daemon tells <code>containerd</code> and <code>runc</code> to create and start the container (remember the Docker architecture we discussed in Part -1). Once its done you will be able to get inside the container.</p>
<p>A container runs <strong>as long as the main app is running</strong>. If the app exists, the container stops. If you stop the container, it stops. If you remove the container, it is gone.</p>
<hr />
<h2>Stopping, starting, and deleting containers</h2>
<p>Common lifecycle commands:</p>
<ul>
<li>Stop a running container:</li>
</ul>
<pre><code class="language-shell">docker container stop &lt;container&gt;
</code></pre>
<ul>
<li>Start a stopped container:</li>
</ul>
<pre><code class="language-bash">docker container start &lt;container&gt;
</code></pre>
<ul>
<li>Remove a container forever:</li>
</ul>
<pre><code class="language-bash">docker container rm &lt;container&gt;
</code></pre>
<hr />
<h2>Working with container processes</h2>
<p>If you are inside a container running <code>/bin/bash</code>, and you kill that main bash process, the container stops.</p>
<p>To exit the container but keep it running:</p>
<ul>
<li>Press: <code>Ctrl-PQ</code></li>
</ul>
<p>Now you are back on your host machine, but the container is still running in the background.</p>
<p>Check running containers:</p>
<pre><code class="language-bash">docker container ls
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/50b699a1-17ed-40d9-bd90-d08997fca346.png" alt="" style="display:block;margin:0 auto" />

<h3>Re-attach using exec</h3>
<p>You can open a new shell inside the running container:</p>
<pre><code class="language-bash">docker container exec -it &lt;container_id&gt; bash
</code></pre>
<p>This creates a <strong>new process</strong> inside the container.</p>
<p>So if you type <code>exit</code> here, the container can still stay alive because the original main process is still running.</p>
<hr />
<h2>Container lifecycle</h2>
<p>You can give a custom name to your container like this</p>
<pre><code class="language-bash">docker container run --name boo -it ubuntu:latest /bin/bash
</code></pre>
<p>After running it, we will be inside the container. Let's create a file here</p>
<pre><code class="language-bash">cd tmp
echo "Hello World" &gt; newfile
ls -l
cat newfile
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/c4876450-d67b-4d02-824e-1437a05f24ed.png" alt="" style="display:block;margin:0 auto" />

<p>Detach without stopping it:</p>
<ul>
<li><code>Ctrl-PQ</code></li>
</ul>
<p>Stop it:</p>
<pre><code class="language-bash">docker container stop boo
</code></pre>
<p>Start it again:</p>
<pre><code class="language-bash">docker container start boo
</code></pre>
<p>Go back inside:</p>
<pre><code class="language-bash">docker container exec -it boo bash
</code></pre>
<p>Check the file:</p>
<pre><code class="language-bash">cd tmp
ls -l
cat newfile
</code></pre>
<p>You will see the file is still there.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/c5a3bad8-3294-4928-a94c-3149c0d42eb3.png" alt="" style="display:block;margin:0 auto" />

<p>So what did we learn from this?</p>
<h3>Two important notes</h3>
<ol>
<li><p>That the data lives on the Docker host. If the host fails, the data is lost.</p>
</li>
<li><p>Containers are meant to be <strong>immutable</strong>, so writing data inside them is not a good habit.</p>
</li>
</ol>
<p>That is why Docker has <strong>volumes</strong>, which store data outside the container. We will look into volumes in the upcoming blog.</p>
<hr />
<h2>Stopping containers gracefully</h2>
<p>There is a big difference between stopping and force-killing.</p>
<ul>
<li><p><code>docker container stop</code> is polite.</p>
<p>It sends a <code>SIGTERM</code> to the main process (PID 1) and gives it time (usually 10 seconds) to shut down cleanly.</p>
<p>If it does not stop in time, Docker sends <code>SIGKILL</code>.</p>
</li>
<li><p><code>docker container rm -f</code> is not polite.</p>
<p>It kills the container right away (no clean shutdown).</p>
</li>
</ul>
<hr />
<h2>Restart policies</h2>
<p>It’s often a good idea to run containers with a restart policy. Why do we care? Because in the real world, we might have some container that crashes or stops suddenly, and we want them to restart automatically. This is where Restart policies come into play.</p>
<p>Restart policies enable Docker to automatically restart them after certain events or failures have occurred.</p>
<p>Common policies are:</p>
<ul>
<li><p><code>always</code> - If we attach this policy to the container, Docker will always restart the stopped container if it's closed by Docker or fails.</p>
</li>
<li><p><code>unless-stopped</code></p>
</li>
<li><p><code>on-failed</code> (often written as <code>on-failure</code>)</p>
</li>
</ul>
<p>Example: Let's create a container with the always policy attached.</p>
<pre><code class="language-bash">docker container run --name zoo -it --restart always ubuntu:lastest bash
</code></pre>
<p>Now If you type <code>exit</code>, and get out of the container, the container stops, but Docker starts it again because the policy is <code>always</code>. Try <code>docker container ls</code> and see.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/907a2692-2f68-4346-86be-eb733dbd375f.png" alt="" style="display:block;margin:0 auto" />

<p>See how the container was created 19 seconds ago, but has only been up for 11 seconds. This is because the <code>exit</code> command killed it and Docker restarted it. Be aware that Docker has restarted the same container and not created a new one.</p>
<p>Difference between <code>always</code> and <code>unless-stopped</code>:</p>
<ul>
<li><p><code>always</code>: restarts even after Docker daemon restarts</p>
</li>
<li><p><code>unless-stopped</code>: does not restart after daemon restart if it was already in a stopped state</p>
</li>
</ul>
<p>Let's see it in action: Create two container with name <code>always</code> and <code>unless-stopped</code> with respective policies attached</p>
<pre><code class="language-shell">docker container run -d --name always \                                                               
--restart always \
ubuntu:latest sleep 1d
</code></pre>
<pre><code class="language-shell">docker container run -d --name unless-stopped \                                                               
--restart always \
ubuntu:latest sleep 1d
</code></pre>
<p>Now check with <code>docker container ls</code></p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/a7b2e1f6-48f5-4988-a3d5-25acb0829563.png" alt="" style="display:block;margin:0 auto" />

<p>Now lets run, and restart the Docker</p>
<pre><code class="language-shell">docker container stop always unless-stopped
</code></pre>
<p>Now run</p>
<pre><code class="language-shell">docker container ls -a
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/ef2ad472-e9da-4598-8dc1-34144678303a.png" alt="" style="display:block;margin:0 auto" />

<p>Notice that the “always” container has been restarted but the "unless-stopped" container has not.</p>
<p>The <code>on-failure</code> policy will restart a container if it exits with a non-zero exit code.</p>
<hr />
<p>Let's clean up everything and remove all the container now.</p>
<pre><code class="language-bash">docker container rm $(docker container ls -aq) -f
</code></pre>
<p>Be careful with this command as this command will remove every container running forcefully.</p>
<hr />
<h2>Quick list of useful container commands</h2>
<ul>
<li><p><code>docker container run</code> — start a new container</p>
</li>
<li><p><code>docker container ls</code> — list running containers</p>
</li>
<li><p><code>docker container ls -a</code> — list all containers (including stopped)</p>
</li>
<li><p><code>docker container exec</code> — run a command inside a running container</p>
</li>
<li><p><code>docker container stop</code> — stop a container</p>
</li>
<li><p><code>docker container start</code> — start a stopped container</p>
</li>
<li><p><code>docker container rm</code> — delete a container</p>
</li>
<li><p><code>docker container inspect</code> — detailed container info</p>
</li>
<li><p><code>Ctrl-PQ</code> — detach without stopping the container</p>
</li>
</ul>
<hr />
<h2>Conclusion</h2>
<p>We saw how container is beneficial and works with all the important commands to start, stop, and remove. Also we learned how restart policies plays an important role in Docker ecosystem.</p>
<p>In the next blog, we will implement everything we learned so far by containerizing the application. Untill then...</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/e80376a7-df56-4571-b2fc-361d914185e9.png" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[Diving into Docker (Part 2): Images]]></title><description><![CDATA[In the previous blog...
We learned about some fundamental concepts of Docker and its architecture. We saw why we need Docker in the first place and how it is solving the problems and making things eas]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-2-images</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-2-images</guid><category><![CDATA[Cloud Computing]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[containers]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Wed, 11 Mar 2026 22:51:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/d11bbd88-3e1d-4c32-9fb4-1735528624fd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>In the previous blog...</h2>
<p>We learned about some fundamental concepts of Docker and its architecture. We saw why we need Docker in the first place and how it is solving the problems and making things easier than the good old VMs.</p>
<p>In this blog, we are going to understand the core part of Docker, Images. We will see the difference between Images and Containers, and also learn about the Image registries.</p>
<p>We will see the commands that help us pull, create, and run the Docker image and much more. So let's get started</p>
<hr />
<h3>What is a Docker image?</h3>
<p>A <strong>Docker image</strong> is a ready-to-use package that has everything an app needs to run, such as:</p>
<ul>
<li><p>The application code</p>
</li>
<li><p>The app’s required libraries</p>
</li>
<li><p>Basic operating system files</p>
</li>
</ul>
<p>If you are a developer, you can think of an image like a <strong>class blueprint</strong>. You use it to create real running things.</p>
<p>Docker images are mainly used at <strong>build time</strong>, while <strong>containers</strong> are what you use at <strong>run time</strong> when the app is actually running.</p>
<hr />
<h3>Where do Docker images come from?</h3>
<p>Most of the time, you do not create images from scratch. You <strong>pull</strong> them from a place called an <strong>image registry,</strong> and the most common registry is <strong>Docker Hub.</strong></p>
<p>So when we pull an image from the Docker Hub, the Docker daemon downloads it to your computer (your Docker host). After that, Docker can use it to start one or more containers</p>
<hr />
<h3>Images are made of layers</h3>
<p>A Docker image is not one single file. It is built from many <strong>read-only layers</strong> stacked on top of each other.</p>
<p>Inside these layers, we have a small cut-down operating system and all the required files and dependencies for the app. Which means you don't get the full system with all the things.</p>
<p>Docker stacks the layers and shows them as one unified image.</p>
<p>When you pull an image like this:</p>
<pre><code class="language-bash">docker image pull ubuntu:latest
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/ae6db394-8079-484e-91dc-a798c7375048.png" alt="" style="display:block;margin:0 auto" />

<p>Each line that ends with <strong>“Pull complete”</strong> is basically one layer being downloaded.</p>
<p>You can also inspect layers using:</p>
<pre><code class="language-bash">docker image inspect ubuntu:latest
</code></pre>
<p>The idea here is, every image starts with a <strong>base layer,</strong> and when we add things (like installing Python or adding your app code), Docker adds new layers on top. For example, we have this Ubuntu image. And then we add Python to it, and then we add source code.</p>
<p>Now, the final image becomes a stack of layers in that order.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/97f2d1e4-85a2-4b94-a9d0-e5c81f01710d.png" alt="Image from Docker Deep Dive Zero to Docker in a single book - Nigel Poulton" style="display:block;margin:0 auto" />

<p>(Source: Docker Deep Dive - Nigel Poulton)</p>
<p>Docker also has a system called a storage driver that handles stacking these layers. There are many drivers, but the experience feels the same to you.</p>
<hr />
<h3>Images and containers: how they connect</h3>
<p>We will learn about containers in the next blog, but for now, just understand that you can start containers from an image using commands like, <code>docker container run</code> and <code>docker service create.</code> Once a container is created from an image, the image and container are linked, and we <strong>cannot delete the image</strong> until all containers using it are stopped and deleted. If you try, Docker will give an error.</p>
<p>Also, the purpose of a container is usually to run <strong>one app or one service</strong>, so the image should only include what that app needs.</p>
<p>For example:</p>
<ul>
<li><p>If the app does not need a shell, the image should not include many shells</p>
</li>
<li><p>Docker images also do not include a kernel. All containers on a machine share the <strong>host machine’s kernel</strong></p>
</li>
</ul>
<hr />
<h3>Image registries and repositories</h3>
<ul>
<li><p>An <strong>image registry</strong> is a central place to store images (for example, Docker Hub).</p>
</li>
<li><p>Image registries contain one or more image repositories. In turn, image repositories contain one or more images.</p>
</li>
</ul>
<p>Docker Hub has two types of repositories:</p>
<ul>
<li><p><strong>Official repositories</strong></p>
<ul>
<li>Checked and curated by Docker</li>
</ul>
</li>
<li><p><strong>Unofficial repositories</strong></p>
<ul>
<li><p>Can be risky</p>
</li>
<li><p>Do not assume they are safe, well-documented, or built correctly</p>
</li>
</ul>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2faceb45-e17b-4626-8ecd-6383fcd240d1.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h3>Image names and tags (how you pull the right one)</h3>
<p>For official images, pulling is usually:</p>
<pre><code class="language-bash">docker image pull &lt;repository&gt;:&lt;tag&gt;
</code></pre>
<p>Examples:</p>
<pre><code class="language-bash">docker image pull alpine:latest
docker image pull redis:latest
docker image pull mongo:4.2.6
docker image pull busybox:latest
</code></pre>
<p>If you run:</p>
<pre><code class="language-bash">docker image pull alpine
</code></pre>
<p>Docker assumes you mean:</p>
<ul>
<li><code>alpine:latest</code></li>
</ul>
<h4>Two important notes about <code>latest</code></h4>
<p>If you do not specify a tag, Docker assumes <code>latest</code>. And If the repo does not have a <code>latest</code> tag, the pull will fail.</p>
<p><code>latest</code> does not mean “newest”. It is just a label. For example, in Alpine, the newest is often tagged <code>edge</code>. So be careful when using <code>latest</code>.</p>
<hr />
<h3>Pulling images from unofficial repos</h3>
<p>Same idea, but you include the username or org name:</p>
<pre><code class="language-bash">docker image pull someusername/imagename:version
</code></pre>
<hr />
<h3>Pulling from other registries (not Docker Hub)</h3>
<p>If the image is in another registry, like there are google registries too, so to get that we include the registry’s DNS name:</p>
<pre><code class="language-bash">docker image pull gcr.io/google-containers/git-sync:v3.1.5
</code></pre>
<hr />
<h3>Searching Docker Hub from the command line</h3>
<p>You can search Docker Hub using:</p>
<pre><code class="language-bash">docker search alpine
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/2a7660c8-c658-47d7-ac7f-b7759bd77982.png" alt="" style="display:block;margin:0 auto" />

<ul>
<li><p>It searches for repos that match a string in the <strong>NAME</strong> field</p>
</li>
<li><p><strong>NAME</strong> is the repository name</p>
</li>
</ul>
<p>To show only official repos:</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/547878ea-422e-43d2-9bc8-e250949e56fe.png" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-bash">docker search alpine --filter "is-official=true"
</code></pre>
<hr />
<h3>Pulling images by digest</h3>
<p>Pulling by tag is common, but there is a problem: <strong>Tags can change.</strong> Someone can push a new version using the same tag. Then you might not know which exact version your running systems are using</p>
<p>For example, you have <code>exampleimage:1.5</code> with a known bug. You fix it and push it again as <code>exampleimage:1.5</code>Now two different images have used the same tag name over time. It becomes hard to know what is running where</p>
<p>Docker uses a content-based ID called a <strong>digest,</strong> which is a cryptographic hash.</p>
<p>The idea here is that if the image content changes, the digest changes. So digests are <strong>unchangeable</strong>, and they uniquely identify the exact image</p>
<p>When you pull an image, Docker often shows the digest:</p>
<pre><code class="language-bash">docker image pull alpine
</code></pre>
<p>You can list digests locally:</p>
<pre><code class="language-bash">docker image ls --digests ubuntu
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/c9c094f9-7b03-4b52-8c67-0711faabe3fd.png" alt="" style="display:block;margin:0 auto" />

<p>And you can pull the exact same image again using the digest:</p>
<pre><code class="language-bash">docker image pull ubuntu@sha256:d1e2e92...7e495eff4f9
</code></pre>
<p>This makes sure you get <strong>exactly</strong> the image you expect.</p>
<hr />
<h3>Multi-architecture images</h3>
<p>Different machines can have different Operating systems (Linux, Windows), different CPU types (x64/amd64, ARM, etc.).</p>
<p>For example, your laptop might be <strong>Linux on x64,</strong> A Raspberry Pi is <strong>Linux on ARM,</strong> A Windows server might be <strong>Windows on x64</strong></p>
<p>Before multi-architecture support, you had to <strong>manually pick the right image</strong>, which was confusing.</p>
<p>So, when you run</p>
<pre><code class="language-bash">docker pull golang:latest
</code></pre>
<p><strong>Docker automatically detects your OS and CPU</strong>, pulls the correct version for your system. You don’t need to specify anything.</p>
<h4>How does Docker do this?</h4>
<p>Docker uses two important things in the registry:</p>
<ol>
<li><p><strong>Manifest List:</strong> This is nothing but a list of supported platforms for that image tag</p>
<ul>
<li>Example: Linux/amd64, Linux/arm, Windows/amd64</li>
</ul>
</li>
<li><p><strong>Manifests:</strong> Each platform has its own Manifest. And that Manifest lists the layers and configuration for that platform</p>
</li>
</ol>
<p>So the Flow is:</p>
<pre><code class="language-bash">docker pull golang:latest
        |
Docker checks manifest list
        |
Finds match for your OS + CPU
        |
Downloads correct layers
</code></pre>
<p>Docker also lets you build images for other CPU types using <code>buildx</code>.</p>
<p>Example:</p>
<pre><code class="language-bash">docker buildx build --platform linux/arm/v7 -t myimage:arm-v7 .
</code></pre>
<p>You can even build ARM images while working on an x64 machine. How cool is that!!</p>
<hr />
<h3>Deleting Docker images</h3>
<p>To delete an image:</p>
<pre><code class="language-bash">docker image rm 02674b9cb179
</code></pre>
<p>Delete multiple images:</p>
<pre><code class="language-bash">docker image rm f70734b6a266 a4d3716dbb72
</code></pre>
<p><strong>Important rules:</strong></p>
<ul>
<li><p>Deleting an image removes the image and its layers.</p>
</li>
<li><p>But if a layer is shared by multiple images, it will not be removed until all those images are deleted.</p>
</li>
<li><p>If an image is used by a running container, Docker will not let you delete it</p>
<ul>
<li>Stop and delete the container first</li>
</ul>
</li>
</ul>
<p>Shortcut to delete all images (force):</p>
<pre><code class="language-bash">docker image rm $(docker image ls -q) -f

# Here $(docker image ls -q) will list all the images. Its a shortcut.
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>This is more than enough for you to understand everything about Docker images right now. In the next blog, we will dive into Containers and see what a container is and how it actually works under the hood. Until then...</p>
<p><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjFtZG8yY3V6azR5ejRoY2p4eXltcWdzcDVrMXVhcjlzdnVrcG5zayZlcD12MV9naWZzX3NlYXJjaCZjdD1n/2nlbKhgnvAK3sR8ffw/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjFtZG8yY3V6azR5ejRoY2p4eXltcWdzcDVrMXVhcjlzdnVrcG5zayZlcD12MV9naWZzX3NlYXJjaCZjdD1n/2nlbKhgnvAK3sR8ffw/giphy.gif</a></p>]]></content:encoded></item><item><title><![CDATA[Diving Into Docker (Part 1): The Big Picture]]></title><description><![CDATA[Introduction
So, I've been reading this book called Docker Deep Dive Zero to Docker by Nigel Poulton. Why? Because I've been working on mobile, web, and cloud applications for quite a long time now. A]]></description><link>https://dhruvnakum.xyz/diving-into-docker-part-1</link><guid isPermaLink="true">https://dhruvnakum.xyz/diving-into-docker-part-1</guid><category><![CDATA[Docker]]></category><category><![CDATA[containers]]></category><category><![CDATA[virtual machine]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Orchestration]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Wed, 11 Mar 2026 02:08:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/162e365e-d62f-4154-9d59-9e38afab46f3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>So, I've been reading this book called <strong>Docker Deep Dive Zero to Docker</strong> by <strong>Nigel Poulton</strong>. Why? Because I've been working on mobile, web, and cloud applications for quite a long time now. And I really wanted to know how Docker works internally and how it does the magic.</p>
<p>And then I came across this book and thought to give it a try because I love reading, and to be honest, I hardly read technical books to learn about something personally (well, except college and study books, of course lol). So while reading it, I was also making notes for myself.</p>
<p>I will be sharing everything I learned from this book. I will be using the book to explain and rewrite things, making things simpler to understand, because some of the things later on in this book took a while for me to understand. I will also be using Nano Banana to create visuals to help you better understand because I don't want to waste time on graphics too much. And obiously AI does better job than me now in designing these things ;)</p>
<p>So, let's get started without further ado.</p>
<hr />
<h2>The Big Picture</h2>
<p>A few years ago, running apps looked very different. Most companies ran <strong>one application per server</strong>. If the business needed a new app, the IT team often had to buy a new server. This cost a lot of money and wasted resources, because many servers had unused CPU and RAM.</p>
<p>Then <strong>virtual machines (VMs)</strong> became popular.</p>
<h3>VMs Solved One Problem, But Created Another</h3>
<p>VMs made it possible to run <strong>multiple applications on one server</strong>. That was a big improvement. But there was a downside too, which were</p>
<ul>
<li><p>Each VM needs its <strong>own full operating system.</strong></p>
</li>
<li><p>That OS uses <strong>CPU and RAM</strong> even when the app is small.</p>
</li>
<li><p>Sometimes each OS also <strong>needs its own license.</strong></p>
</li>
<li><p>VMs can be <strong>slow to boot.</strong></p>
</li>
<li><p><strong>Moving VMs across machines</strong> is not always smooth.</p>
</li>
</ul>
<p>So even though VMs helped, they still had a lot of overhead.</p>
<h3>Containers: A Lighter Way To Run Apps</h3>
<p>To solve the above problem, <strong>containers</strong> come into the picture. What is a container? For now, just think that a container is similar to a VM in one way. It runs an application in an isolated environment.</p>
<p>But the key difference is that <strong>Containers share the host machine’s kernel.</strong> They <strong>do not need a full OS per container</strong></p>
<p>And because of this, containers are Faster to start, more lightweight, and Easier to move around, which was the problem in VMs, remember?</p>
<p>Google has used container tech for a long time. But for many companies, containers were still too complex to use directly. To address this complexity and make things easier for everyone, Docker Inc. began developing Docker.</p>
<hr />
<h2>What Does “Docker” Mean?</h2>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/5707cdaa-ddaa-429a-829b-3b19a82abdc0.png" alt="" style="display:block;margin:0 auto" />

<p>When people say “Docker”, they might mean two things:</p>
<ol>
<li><p><strong>Docker, Inc.</strong> - the company</p>
</li>
<li><p><strong>Docker, the technology</strong> - the tool that creates and runs containers</p>
</li>
</ol>
<p><strong>Docker</strong>, the technology runs on Linux and Windows, and helps you build, run, and manage containers.</p>
<hr />
<h2>Docker Architecture</h2>
<p>There are three things that we need to be aware of when we talk about Docker.</p>
<ol>
<li><p><strong>Docker Runtime</strong></p>
</li>
<li><p><strong>Docker Daemon</strong></p>
</li>
<li><p><strong>Docker Orchestrator</strong></p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/80fe5be2-c993-4296-a44e-cab1d3e308b6.png" alt="" style="display:block;margin:0 auto" />

<p>Let's see each one of them in detail now.</p>
<h3>Docker Runtime</h3>
<p>Docker uses a “tiered runtime” setup. <strong>Low-level</strong> and <strong>High-level runtime.</strong></p>
<blockquote>
<p>When I say <strong>Docker uses a tiered runtime architecture</strong>, I mean that Docker splits responsibilities between different components instead of having one big program do everything.</p>
</blockquote>
<h4>Low-level runtime: <code>runc</code></h4>
<ul>
<li>This talks to the operating system. Starts and stops containers. Each container typically has a <code>runc</code> instance managing it.</li>
</ul>
<h4>High-level runtime: <code>containerd</code></h4>
<ul>
<li>This manages the whole container lifecycle. It pulls images. Sets up networking and calls <code>runc</code> when needed</li>
</ul>
<p>You do not need to memorize this on day one, but it helps to know Docker has layers.</p>
<h3>Docker Daemon</h3>
<p>Docker Daemon sits above <code>containerd</code> and performs higher-level tasks, such as exposing the Docker remote API, managing images, volumes, and networks, and more.</p>
<p>The Docker daemon’s main job is to provide an easy-to-use standard interface that abstracts the lower levels.</p>
<h3>Docker Orchestrator</h3>
<p>Before we understand this layer, we need to understand what orchestration means.</p>
<p>You see, running one container is easy. But in real apps, you often need many containers, like web apps, databases, caches, and background workers.</p>
<p><strong>Orchestration</strong> means managing all of those automatically. If you have seen any performance in an orchestra where the orchestrator manages all the musicians, the same concept applies to the Docker too.</p>
<ul>
<li>The orchestrator, Start the containers, restart if they crash, scale up when traffic increases, and connect them properly</li>
</ul>
<p>Docker has its own orchestrator called <strong>Docker Swarm</strong>, but today most teams use <strong>Kubernetes</strong>.</p>
<h4>Kubernetes in one line (because we are not going into the details right now)</h4>
<p>Kubernetes is the most popular platform for deploying and managing containerized apps.</p>
<hr />
<h2>OCI: Why Standards Matter</h2>
<p>There is also something called the <strong>Open Container Initiative (OCI)</strong>. In simple terms, it's nothing but a government council that sets standards for the image and runtime formats.</p>
<p>An analogy often used to describe these two standards is <strong>rail trails.</strong></p>
<p>This is useful, and it’s fair to say that the two <strong>OCI</strong> specifications have had a major impact on the architecture and design of the core Docker product.</p>
<hr />
<h2>Installing Docker</h2>
<p>Docker is available everywhere to download. There are Windows, Mac, and Linux applications. You can install it in the cloud, on premises, and on your laptop. And there are manual, scripted, and wizard-based installs, too. There literally are loads of ways and places to install Docker.</p>
<h2>Docker Desktop</h2>
<p>This is the main application we use for everything. Go to <a href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a> website and download it on your respective operating system. Once installed, you will see the interface something like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/8ce1e7c8-52b8-407e-bfa7-793e135fc82b.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>Docker’s Main Parts</h2>
<p>So when you install Docker, you mainly work with two pieces: <strong>Docker Client</strong> and <strong>Docker Daemon</strong></p>
<h3>1) Docker Client</h3>
<p>This is what you interact with, usually from the terminal.</p>
<p>Open your terminal and run the command below. You will see the current Docker version installed in your system.</p>
<p>Example:</p>
<pre><code class="language-plaintext">docker version
</code></pre>
<h3>2) Docker Daemon</h3>
<p>This is the background service that does the real work:</p>
<ul>
<li><p>pulls images</p>
</li>
<li><p>runs containers</p>
</li>
<li><p>manages networks and volumes</p>
</li>
<li><p>exposes the Docker API</p>
</li>
</ul>
<p>The <strong>client talks to the daemon</strong>. This is the high-level explanation. Now, let's get into the details</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/6c78378b-0ea8-42c9-8eed-0bb83f2c8fbe.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>The Two Core Docker Objects: Images and Containers</h2>
<h3>Docker Image</h3>
<p>A Docker image is like a package that contains:</p>
<ul>
<li>a small filesystem like Linux files, or it can be your app, or the dependencies needed to run the app</li>
</ul>
<p>The important thing here is that it's an image, not a running instance. It is more like a <strong>blueprint.</strong> You can think of a Docker Image as a <strong>Class</strong> in the world of programming. And when you create an Object of that Class, it becomes a real thing and gets memory allocated in the system. In this case, that object is Container.</p>
<p>Getting an image onto your Docker host is called <strong>pulling.</strong> So whenever you want to get the image, you run the command below,</p>
<pre><code class="language-plaintext">docker image pull ubuntu:latest
</code></pre>
<p>And from where this image will come from, you might ask? We will talk about it in the upcoming article, don't worry. For now, just know that it comes somewhere from the internet. And so, after pulling the image, you will see something like this.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/320f94eb-7dec-4050-974b-962f29254743.png" alt="" style="display:block;margin:0 auto" />

<p>To check whether you successfully installed that image, there are two ways: First, to run the command below in your terminal</p>
<pre><code class="language-plaintext">docker image ls
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/3b729d3c-0d4c-4933-bf91-6cf80cf0e352.png" alt="" style="display:block;margin:0 auto" />

<p>Each image gets its own unique ID. When referencing images, you can refer to them using either IDs or names</p>
<p>And the second way is to check the Docker Desktop</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/62e2ee1f-8f86-48c2-8c10-96582d46033b.png" alt="" style="display:block;margin:0 auto" />

<h3>Docker Container</h3>
<p>A container is a <strong>running instance</strong> created from an image.</p>
<p>So:</p>
<ul>
<li><p><strong>Image = blueprint</strong></p>
</li>
<li><p><strong>Container = running app</strong></p>
</li>
</ul>
<p>Now that we have an image pulled locally, we can use the Docker container run command to launch a container from it.</p>
<pre><code class="language-plaintext">docker container run -it ubuntu:latest /bin/bash
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/828ca207-3728-4004-a853-fabe2db9cc46.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p>Let's understand the command here first:</p>
<p><code>docker container run</code> tells the Docker daemon to start a new container.</p>
<p><code>-it</code> flag tells Docker to make the container interactive and to attach the current shell to the container’s terminal.</p>
<p><code>ubuntu:latest</code> command tells Docker that we want the container to be based on the ubuntu:latest image.</p>
<p><code>/bin/bash</code> tell Docker which process we want to run inside of the container. For linux we are running a Bash shell.</p>
</blockquote>
<p>As you can see, after running the command, we got inside the Ubuntu container. And it's a real Ubuntu image. So you can run the command you run on Ubuntu. But not all of them right now. Why? We will come to it later, don't worry.</p>
<blockquote>
<p>You can exit the container without terminating it by Ctr - PQ command</p>
</blockquote>
<p>If you want to see all the containers, you can run</p>
<pre><code class="language-plaintext">docker container ls
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/67e33eb7-4769-44b5-8428-f57659ef8534.png" alt="" style="display:block;margin:0 auto" />

<p>Now, if you have exited the container, you can again get back into it using the <code>exec</code> command</p>
<pre><code class="language-plaintext">docker container exec -it 0acc2d5f2fef bash
</code></pre>
<p>We used the <code>-it</code> options to attach our shell to the container’s shell</p>
<p>We can stop and kill the container using the commands below</p>
<pre><code class="language-plaintext">docker container stop &lt;name/id&gt;
</code></pre>
<pre><code class="language-plaintext">docker container rm &lt;name/id&gt;
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/60d634b1de92ef110afdcce9/6b227cad-22cc-4fad-af07-b1e0f72bea7f.png" alt="" style="display:block;margin:0 auto" />

<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">IMPORTANT NOTE:</mark></strong></p>
<ul>
<li>If you are like this right now...</li>
</ul>
<p><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExcjE1MmVtZ3o4bXF1NzJ2aXMzZ3prYmd1dWU3NnY3ZmZ5ZDcwZ3pjbiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/GPg6PuL5RkeyVCD5wk/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExcjE1MmVtZ3o4bXF1NzJ2aXMzZ3prYmd1dWU3NnY3ZmZ5ZDcwZ3pjbiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/GPg6PuL5RkeyVCD5wk/giphy.gif</a></p>
*   Then I would like to say that we just went through the fundamental pieces of Docker in this article. If you didn't understand anything yet, then don't worry. I totally get you. It's hard to grasp all of these at first. But it was necessary for me to give you the big picture about it. So that, when we discuss it in detail, you will know something about it and not feel scared.
    

<hr />
<h2>Conclusion</h2>
<p>We learned about VMs and saw why it's not efficient to use them anymore. We saw how containers can be so much lighter and faster than VMs.</p>
<p>We also saw what Docker is and how it works using its architecture. We learned about OCI and how it helps maintain the standard practice of images and containers.</p>
<p>We also went through some basic commands of Docker, like:</p>
<table>
<thead>
<tr>
<th><code>docker image pull &lt;image-name&gt;</code></th>
<th>to pull an image</th>
</tr>
</thead>
<tbody><tr>
<td><code>docker image ls</code></td>
<td>to list all the installed images</td>
</tr>
<tr>
<td><code>docker container run -it &lt;image-name&gt; &lt;app-name&gt;</code></td>
<td>To start and run the container</td>
</tr>
<tr>
<td><code>docker container ls</code></td>
<td>To list all the installed containers</td>
</tr>
<tr>
<td><code>docker container exec -it &lt;container_name&gt; bash</code></td>
<td>To attach the terminal to the running container's terminal</td>
</tr>
<tr>
<td><code>docker container stop &lt;nameid&gt;</code></td>
<td>To stop the running container</td>
</tr>
<tr>
<td><code>docker container rm &lt;nameid&gt;</code></td>
<td>To remove/kill the container</td>
</tr>
</tbody></table>
<p>This big picture view should help you with the upcoming article, where we will dig deeper into images and containers.</p>
<p>See you in the next article, until then....</p>
<p><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjFtZG8yY3V6azR5ejRoY2p4eXltcWdzcDVrMXVhcjlzdnVrcG5zayZlcD12MV9naWZzX3NlYXJjaCZjdD1n/2nlbKhgnvAK3sR8ffw/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjFtZG8yY3V6azR5ejRoY2p4eXltcWdzcDVrMXVhcjlzdnVrcG5zayZlcD12MV9naWZzX3NlYXJjaCZjdD1n/2nlbKhgnvAK3sR8ffw/giphy.gif</a></p>]]></content:encoded></item><item><title><![CDATA[Ship It Like a Pro: Node.js on EC2 with Caddy & systemd]]></title><description><![CDATA[Introduction

I've been learning a lot about AWS lately, and to be honest, there's a lot to understand and learn. I decided to take a little break and try to implement what I've learned so far. At the same time, I'm working on a project that's still ...]]></description><link>https://dhruvnakum.xyz/ship-it-like-a-pro-nodejs-on-ec2-with-caddy-and-systemd</link><guid isPermaLink="true">https://dhruvnakum.xyz/ship-it-like-a-pro-nodejs-on-ec2-with-caddy-and-systemd</guid><category><![CDATA[AWS]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[deployment]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[ec2]]></category><category><![CDATA[Amazon Web Services]]></category><category><![CDATA[Ubuntu 22.04]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Mon, 10 Nov 2025 04:03:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762747315634/05e6012f-75a4-4cb8-859b-02276fbd9a0c.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>I've been learning a lot about AWS lately, and to be honest, there's a lot to understand and learn. I decided to take a little break and try to implement what I've learned so far. At the same time, I'm working on a project that's still in progress, and I'll be announcing it soon. I have a backend app in Node.js for this project and wanted to deploy it. So, I thought, why not deploy it on AWS to test my knowledge and see if I've learned anything?</p>
</li>
<li><p>A little bit about my Node.js app: I'm using JavaScript, and I have MongoDB running. It's on Atlas in the cloud. I think that's all you need to know. If you have a Node.js application running, you can follow similar steps to make your backend accessible to your frontend application or any third-party consumer.</p>
</li>
<li><p>So, without further ado, let's get started.</p>
</li>
</ul>
<hr />
<h1 id="heading-set-up-an-aws-account">Set up an AWS Account</h1>
<ul>
<li><p>First, we need an AWS account, so I'm assuming you already have one. If not, it's really easy to create one. Go to <a target="_blank" href="https://aws.amazon.com">https://aws.amazon.com</a> and create an account.</p>
</li>
<li><p>It might ask for your credit card information, but don't worry, they won't charge you until you exceed the free-tier limit. In this guide, we won't exceed the free tier, so there's no need to worry. Just add your details, and you're all set.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762472741823/3c3cfdd2-3058-49c7-833c-9de1e99fd12b.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-aws-ec2-instance">AWS EC2 Instance</h1>
<ul>
<li><p>So, we are going to use the AWS EC2 service to deploy our application to AWS. If you're not familiar with EC2, think of it as renting a virtual machine, similar to your laptop or PC. There are many benefits, such as storing data, choosing your operating system, deciding how much computing power you need, selecting the number of CPU cores, RAM, and the type of network you want to use, and more.</p>
</li>
<li><p>You can customize your virtual machine as you like and rent it from AWS, which is the power of the cloud.</p>
</li>
<li><p>What we'll do is copy our local app, with all its files and folders, directly to this virtual machine and then run the app there. The advantage is that anyone with the link can access it, not just us on our local machine.</p>
</li>
</ul>
<hr />
<h1 id="heading-creating-ec2-instance">Creating EC2 Instance</h1>
<ul>
<li>Simply search for EC2 in the search bar and click on it to open the service page.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762538757575/d7139c10-6121-476e-8c2e-2b815254a19f.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Once it's open, you will see a page like this.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762538803979/d9858efc-b7ed-4b14-9b26-11b259f42605.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Simply click on a Launch Instance on Dashboard and give it a name.</li>
</ul>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762538890516/d043f510-ab55-4054-96e9-180bf2771294.png" alt class="image--center mx-auto" /></p>
<ul>
<li>It will also ask you to select the operating system image. Choose Ubuntu and scroll down.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762538972299/36e35659-2e56-4fad-ab3a-c8bed8154c77.png" alt class="image--center mx-auto" /></p>
<ul>
<li>We will use the <code>t2.micro</code> instance because it is part of the free tier. If you need a higher configuration CPU, you can check other instances and select the one that meets your needs.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539062261/6906a284-e72e-4ef7-b92a-a85da7e982e2.png" alt class="image--center mx-auto" /></p>
<ul>
<li>To connect to the instance from our local machine or anywhere else, we need access. To do this, we generate a key pair, which we can use to connect to our AWS instance and launch it in our local environment.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539188902/2daf408e-9be9-4ded-a7a1-3f6733c94449.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Click on "Generate Key Pair," give it a relevant name, and make sure to select the RSA key pair type. Finally, create the key pair, and it will download to your local machine.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539363601/a6b2c185-9b9d-4fe5-b726-466e2e3a1ac0.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>In the network settings, select:</p>
<ul>
<li><p>Allow SSH traffic from - <strong>My IP -</strong> Because we only want to access the instance from our local machine.</p>
</li>
<li><p>Allow HTTPS traffic from the internet (so our application can access our Node.js server using an endpoint or URL with HTTPS)</p>
</li>
<li><p>Allow HTTP traffic from the internet (so our application can access our Node.js server using an endpoint or URL with HTTP)</p>
</li>
</ul>
</li>
<li><p>That's it. Now, review the summary and launch the instance.</p>
</li>
</ul>
<hr />
<h1 id="heading-connecting-via-ssh">Connecting via SSH</h1>
<ul>
<li>Once it’s created, click on <code>Connect to your instance</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539556290/34f5e2ae-0e62-4512-994b-0f5b21d3845f.png" alt class="image--center mx-auto" /></p>
<ul>
<li>This will redirect you to the interface shown below. Here, you can run the instance within AWS Cloud itself and access it, or you can use the SSH Client to access this instance from your local machine, which is what we want.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539589729/85b67bc9-fed8-45df-9603-5ac2026b1283.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Before setting up SSH, remember that we downloaded the <code>Key-Pair</code>. Let's first place it in the correct location.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539669936/624e096c-440f-4ddd-8507-ddc669744599.png" alt class="image--center mx-auto" /></p>
<ul>
<li>I am using a Mac, and I usually store my SSH keys inside the <code>.ssh</code> folder located in the home directory. Let's first navigate to the home directory.</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/
</code></pre>
<ul>
<li>Now, move the key pair from the download folder to the .ssh folder using the <code>mv</code> command below:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539917008/9ca8ba85-d506-4bf8-8203-e4a364988814.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Once it’s done, we are good to go. So let’s follow these instructions.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762539953498/725997fd-ae22-49a8-bc4d-2a31daad1ee4.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Run <code>chmod</code> A command to change the permission to ensure your key is not publicly viewable.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762540006041/71c8f652-afd3-43cd-8b38-7a02ef3672d1.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Now run</p>
</li>
<li><pre><code class="lang-bash">  ssh -i <span class="hljs-string">"&lt;your-key-name&gt;.pem"</span> ubuntu@&lt;your-ip&gt;
</code></pre>
<p>  to connect to the instance we created.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762540063323/36c2dc8b-32e7-46f7-a3cc-f3f7a3cabf33.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Type <code>yes</code> and press Enter</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762540144370/f34169c9-4779-4188-af03-3e090fc2da09.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>As you can see, we are now inside the instance we created. Isn't it cool that we can access it from our local machine?</p>
</li>
<li><p>Now you can perform any tasks that you would normally do on your local machine.</p>
</li>
</ul>
<hr />
<h1 id="heading-installingupdating-packages">Installing/Updating Packages</h1>
<ul>
<li>Now that we have our instance connected, before starting anything, we need to ensure we are using the latest packages in Ubuntu and install any available updates. To do this, we run two commands:</li>
</ul>
<pre><code class="lang-bash">sudo apt update
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762569629578/dc523adf-19a2-483e-bf1f-907d6175a2b0.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Which refreshes package lists (checks for updates) and then</li>
</ul>
<pre><code class="lang-bash">sudo apt upgrade
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762569742182/8fb1e954-8458-4f56-a118-dc81c726a5fe.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Which Installs available updates for installed packages</li>
</ul>
<hr />
<h1 id="heading-installing-nodejs-in-an-ec2-instance">Installing Node.js in an EC2 instance</h1>
<ul>
<li><p>Now that we have all the latest packages, we need to install Node.js (or the backend framework/library you need).</p>
</li>
<li><p>To do this, we need to download and run the NodeSource setup script, which configures the system to install Node.js version 20 from their official repository.</p>
</li>
<li><p>Use the command below to do that:</p>
</li>
</ul>
<pre><code class="lang-bash">curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762569958288/abfe6fae-3158-4145-94fc-1e36dc2897c6.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Once the NodeSource repository is added, we need to install <strong>Node.js</strong> and <strong>npm</strong> (Node.js’s package manager) on our system to use Node.js.</p>
</li>
<li><p>To do this, run the command below</p>
</li>
</ul>
<pre><code class="lang-bash">sudo apt-get install -y nodejs
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762570037013/107a72fd-b2ee-43f0-abd2-9efd75fc4918.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-pushing-local-app-to-ec2">Pushing Local App to EC2</h1>
<ul>
<li>Now that we have the Node environment set up, we can upload our local Node.js app to this instance. We can do this using the SSH connection we already set up.</li>
</ul>
<pre><code class="lang-bash">rsync -avz --exclude <span class="hljs-string">'node_modules'</span> --exclude <span class="hljs-string">'.git'</span> --exclude <span class="hljs-string">'.env'</span> \
  -e <span class="hljs-string">"ssh -i ~/.ssh/your-key.pem"</span> \
  . ubuntu@ip-address:~/app
</code></pre>
<ul>
<li>In simple terms, this command copies the current folder (<code>.</code>) to the remote server’s <code>~/app</code> directory using SSH. It skips unnecessary files like <code>node_modules</code>, <code>.git</code>, and <code>.env</code> because we don't need those.</li>
</ul>
<blockquote>
<p>NOTE: Be sure to replace ‘your-key’ with your SSH key name in the command above, and replace ‘ip-address’ with your actual IP address.</p>
</blockquote>
<ul>
<li>To execute this command, go to your code directory and run the command above.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762570682270/4981a055-758d-4652-b6ca-e7bbe66ee73a.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>If you now run the <code>ls</code> command in your instance's home directory, you will see the <code>app</code> folder has been created.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762570770769/d4ca1d29-2c81-4c8d-a98b-37ee11e59e7e.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762570840301/a9b579be-75a0-41eb-b976-2a61a548d372.png" alt class="image--center mx-auto" /></p>
<p>  And if you use <code>cd</code> to enter it, you will see all your source code.</p>
</li>
</ul>
<hr />
<h1 id="heading-setting-up-environment-env-file">Setting up Environment (<code>.env</code>) File.</h1>
<ul>
<li><p>If you have a database running locally, like PostgreSQL or MySQL, you can install those on this instance just like we did for Node.js.</p>
</li>
<li><p>I have MongoDB running on MongoDB Atlas. So, to allow this instance to access the database, we need to add the instance's IP to the whitelist. Simply copy the instance's IP address and paste it into the IP Access List entry.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762571242267/e0e541c6-c091-40e3-a94e-459a4334adc9.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Now that everything is set up, we need one more file: the <code>.env</code> file. Remember, we excluded it when we transferred our files to the instance.</p>
</li>
<li><p>So let’s create the <code>.env</code>file</p>
</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> app/
sudo vim .env <span class="hljs-comment"># This will create and open .env file</span>
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># .env</span>
<span class="hljs-comment"># paste your environment variables</span>
</code></pre>
<ul>
<li>You can exit the Vim editor by pressing <code>esc</code>, then <code>:</code> (colon), typing <code>wq</code>, and pressing enter.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762624002875/5bb70b47-77b9-4978-9ba5-1d88b454ef93.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>As you can see, we now have the <code>.env</code> file in place.</p>
</li>
<li><p>Before we run our app, let’s make sure we have downloaded all the required packages by running</p>
</li>
</ul>
<pre><code class="lang-bash">npm i
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762624116285/70e3e5ff-cac7-41db-8837-75bd1fde59f3.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Now, if we run the app, it should run without any errors.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762624131648/d43df60e-3c0a-40d0-9887-929ae89f9e7c.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-configuring-security-rules">Configuring Security Rules</h1>
<ul>
<li>To check if it is running, go to the instance dashboard, select your instance, copy the Public IP address, and paste it into your browser.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762624225373/a7974e5f-3fde-40a3-b4e2-5567b391460e.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762624308356/6a25bfde-598a-4a4b-b5fa-1976d5e5c599.png" alt class="image--center mx-auto" /></p>
<ul>
<li>We can't see anything, and it didn't work. Why? Do you remember the security group we set up earlier?</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762624373812/a9d5be7e-a9dd-4d84-8647-ecbe891a9121.png" alt class="image--center mx-auto" /></p>
<ul>
<li>We haven't specified our IP address and because we are accessing it from our machine we must add our IP address with port numner. So, let's add our IP address and the port number to the inbound rules and see if it works now.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762630234179/0d0385a9-a5c1-489f-a153-c878f8e1f6d2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Click on Add Rules and add Custom TCP and specify your IP by selecting My IP.</p>
</li>
<li><p>Now, if you run it, it should work fine. I am hitting <code>/test</code> the endpoint, which shows Hello World text.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762630310591/96b2183e-56d3-4bbf-aa2f-7a4c83195f5c.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-running-app-in-background-systemd">Running App in Background (<code>systemd</code>)</h1>
<ul>
<li><p>But here we have two major problems, and I hope you already know what they are.</p>
</li>
<li><p>One big issue is that it's running on PORT <code>7575</code> and doesn't have a domain name. The second issue is that it's running on our local terminal, so if we close this terminal, we won't be able to access our server using that public IP address.</p>
</li>
<li><p>First, let's address the second issue. To fix that, we need to find a way to run the application in the background so that no matter what we do in the terminal, the server will stay up the whole time.</p>
</li>
<li><p>If you want to run your Node app as a background service, we use the <code>systemd</code> command.</p>
</li>
<li><p>We need to create a service file. This file tells <strong>systemd</strong> (Linux’s init system) how to start, monitor, and restart your Node.js app as a background service, similar to how SSH or MongoDB are managed.</p>
</li>
<li><p>Run the command below to create a new service file.</p>
</li>
</ul>
<pre><code class="lang-bash">sudo vim /etc/systemd/system/myapp.service
</code></pre>
<ul>
<li>And paste lines below in it once Vim is opened</li>
</ul>
<pre><code class="lang-bash">[Unit]
Description=Node.js App 
After=network.target multi-user.target

[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/app
ExecStart=/usr/bin/npm start
Restart=always
Environment=NODE_ENV=production
EnvironmentFile=/home/ubuntu/app/.env
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=myapp

[Install]
WantedBy=multi-user.target
</code></pre>
<ul>
<li><p>In the [Unit] section, we include our app description and ensure our app starts <em>after networking</em> is ready (so Node can bind to a port).</p>
</li>
<li><p>In the [Service] section, we specify how the app will run by including the working directory, environment, and other settings.</p>
</li>
</ul>
<p>Now run</p>
<pre><code class="lang-bash">sudo systemctl daemon-reload
</code></pre>
<ul>
<li>Which Reloads systemd so it notices the new service file.</li>
</ul>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> myapp.service
</code></pre>
<ul>
<li>Enables the service to auto-start on boot.</li>
</ul>
<pre><code class="lang-bash">sudo systemctl start myapp.service
</code></pre>
<ul>
<li>Start it right now (without reboot).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762631451599/094fcd1c-e82a-4831-ba3b-54c0b20efd6b.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">sudo systemctl status myapp.service
</code></pre>
<ul>
<li>Shows current status, logs, and whether it’s running or failed.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762631568531/b15e0f4d-71d1-4fde-b10b-3da884193aa2.png" alt class="image--center mx-auto" /></p>
<ul>
<li>And now, if you kill your terminal/app and still hit the URL, it should work.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762632046949/e294a052-e688-4423-8e1b-ceb4836c0dc0.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762632115976/938cbc5e-eb78-493d-aa15-33ed98f00fc9.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-setting-up-reverse-proxy-using-caddy">Setting up Reverse Proxy (using Caddy)</h1>
<ul>
<li><p>The next step is to allow HTTP access directly, without using PORT 7575. Then, we will add a domain name and an SSL certificate.</p>
</li>
<li><p>To keep your actual web server, <code>localhost:7575</code>, hidden from the world and exposing only the HTTP and HTTPS ports, which are 80 and 443, we use reverse proxies like Nginx or Caddy.</p>
</li>
<li><p>A <strong>reverse proxy</strong> is a server that sits <strong>in front of your application servers</strong> and manages all incoming client requests before sending them to your backend app, such as your Node.js service.</p>
</li>
<li><p>We use this for security purposes. It allows us to add a firewall before requests reach the actual server. It also enables load balancing, as the reverse proxy can distribute requests to multiple servers.</p>
</li>
</ul>
<pre><code class="lang-bash">http://54.86.58.33:7575/
</code></pre>
<p>We do</p>
<pre><code class="lang-bash">https://api.mydomain.com
</code></pre>
<ul>
<li><p>To implement this, there are many services like Nginx and Caddy. For this example, we'll use Caddy because it's easy to set up.</p>
</li>
<li><p>Caddy is a <strong>modern, lightweight reverse proxy and web server</strong>, similar to Nginx but with a major advantage:</p>
</li>
<li><p>Visit this <a target="_blank" href="https://caddyserver.com/docs/install#debian-ubuntu-raspbian">URL</a> and run all the commands.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762632733100/756fe7e1-ae28-4565-8e35-e5c4ed799d46.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf <span class="hljs-string">'https://dl.cloudsmith.io/public/caddy/stable/gpg.key'</span> | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf <span class="hljs-string">'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt'</span> | sudo tee /etc/apt/sources.list.d/caddy-stable.list
chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
</code></pre>
<ul>
<li>Once it is done, let’s remove the custom TCP rule we added in the security group for our IP</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762632841866/a2ecc0bc-249a-4834-96d0-f3c9edf75d34.png" alt class="image--center mx-auto" /></p>
<ul>
<li>And now, if we run</li>
</ul>
<pre><code class="lang-bash">sudo systemctl start caddy
</code></pre>
<ul>
<li>And then visit the IP address <code>54.86.58.33</code> Without mentioning any port, you should see a Caddy page</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762632983642/a5317fd6-d88b-4856-ab39-3ad2c5a87fe9.png" alt class="image--center mx-auto" /></p>
<ul>
<li>But what we want is to forward the traffic to our application instead of showing this page. So, we will edit the Caddy file by opening it using the command below:</li>
</ul>
<pre><code class="lang-bash">sudo vim /etc/caddy/Caddyfile
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762633152753/82190f95-4e98-4934-a962-ba5a69e806fe.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Comment down the <code>root</code> and <code>file_server</code> line and uncomment the <code>reverse_proxy</code> line and add your port.</p>
</li>
<li><p>And now let’s restart Caddy</p>
</li>
</ul>
<pre><code class="lang-bash">sudo systemctl restart caddy
</code></pre>
<ul>
<li>If you again run this URL, you should be able to see your app.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762634080934/e7f74781-5cb3-4a71-b50b-a3d3646c4a16.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>That’s it, now you can use this URL anywhere to access the backend APIs.</p>
</li>
<li><p>You can also set up a custom domain name and attach it to this current IP address (for example, example.com) or something like this using the Route53 service.</p>
</li>
</ul>
<hr />
<h1 id="heading-conclusion">Conclusion</h1>
<ul>
<li><p>Thank you for taking the time to read my blog. I hope you enjoyed it and learned something new. I'll be sharing more about AWS soon as I continue to learn. Keep learning!!</p>
</li>
<li><p>Until then…</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a><strong>,</strong> <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a><strong>, and</strong> <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a><strong>.</strong></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Building Scalable GO Application With Docker, AWS, and GitHub Actions]]></title><description><![CDATA[Introduction

In the last part, we successfully put the Go application in a Docker container. Now, we need to deploy it so others can access it.

First, we need to upload our Docker application to Docker Hub. We'll start with that and then set up a G...]]></description><link>https://dhruvnakum.xyz/building-scalable-go-application-with-docker-aws-and-github-actions-1-1</link><guid isPermaLink="true">https://dhruvnakum.xyz/building-scalable-go-application-with-docker-aws-and-github-actions-1-1</guid><category><![CDATA[golang]]></category><category><![CDATA[backend]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[Redis]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Sat, 15 Feb 2025 22:25:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739579318898/a9c508b1-5b95-4dfa-bac9-d569c7cd54c1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>In the last part, we successfully put the Go application in a Docker container. Now, we need to deploy it so others can access it.</p>
</li>
<li><p>First, we need to upload our Docker application to Docker Hub. We'll start with that and then set up a GitHub workflow action to help us deploy our application to AWS EC2.</p>
</li>
<li><p>You might wonder why we use GitHub Actions. In real-world projects, things change often, and you can't manually deploy the application every time. To automate this, we use a tool like GitHub Actions.</p>
</li>
<li><p>Let's begin with Docker Hub, and then we'll create the workflow file.</p>
</li>
</ul>
<hr />
<h1 id="heading-upload-go-application-to-dockerhub">Upload Go Application to DockerHub</h1>
<ul>
<li><ul>
<li><p>DockerHub is like GitHub but for Docker images. It's an online place where developers can find and share Docker images.</p>
<p>    * You make your custom image on your computer and push it to DockerHub for others to use.</p>
<p>    * As developers, we just need to pull these images using the command <code>docker pull</code>, and we're ready to go.</p>
<p>    * Now, let's upload our Go application to DockerHub.Step 1: Login to Dockerhub</p>
</li>
</ul>
</li>
<li><p>First, we need to log into the docker hub in order to upload.</p>
</li>
<li><p>Run the below command.</p>
</li>
</ul>
<pre><code class="lang-bash">docker login
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739417596170/b7a870f2-f440-4c08-a73a-6843d6316bf1.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>This takes you to the browser where you can log in or sign up. Once you do that, you'll see a message confirming your login was successful.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739417784101/9f64319c-18fb-4a19-a2f9-81bfff37de27.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Once you are logged in, go to <code>hub.docker.com</code></li>
</ul>
</li>
</ul>
<h2 id="heading-create-repository">Create Repository</h2>
<ul>
<li>Just like GitHub needs a repository to store code, Docker Hub needs a repository to store Docker images. Go to the <code>Repositories</code> tab in the Navbar.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739417959111/465bb798-4b5e-473a-aa3d-a1c789aa56bc.png" alt class="image--center mx-auto" /></p>
<ul>
<li>And create a public repository. I already have one, so I won't create it again.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739419153043/bda81966-556d-456f-b578-5d9345b65695.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-push-image">Push Image</h2>
<ul>
<li>Once you've created the repository, you can push the image we made using the <code>docker push</code> command. But first, we need to tag our local image as <code>latest</code>, as shown below.</li>
</ul>
<pre><code class="lang-bash">docker tag anonymous-go dhruvnakum/anonymous-go:latest
</code></pre>
<ul>
<li>And now let’s push it</li>
</ul>
<pre><code class="lang-bash"> docker push dhruvnakum/anonymous-go:latest
</code></pre>
<ul>
<li><p>Replace <code>dhruvnakum</code> with your username, and if you named the repository differently, use that name instead.</p>
</li>
<li><p>After you run this, the image will be successfully pushed to the repository we just created.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739516794707/deb48b3b-d513-454f-8c96-66a5e1e780bf.png" alt class="image--center mx-auto" /></p>
<p>  Now, let's create a workflow to automate deployment.</p>
</li>
</ul>
<hr />
<h1 id="heading-creating-the-github-actions-workflow">Creating the GitHub Actions Workflow</h1>
<ul>
<li>To automate deployment, we will set up a GitHub Actions workflow.</li>
</ul>
<h3 id="heading-create-the-workflow-file">Create the Workflow File</h3>
<ul>
<li>In the project, create a new file at <code>.github/workflows/cicd.yml</code>.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739514002340/754732d8-9a9b-4fcf-80d0-a868ec8f2b7e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-define-the-cicd-pipeline">Define the CI/CD Pipeline</h3>
<pre><code class="lang-bash">name: Deploy Go Application

on:
  push:
    branches: 
      - ec2

<span class="hljs-built_in">jobs</span>:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Source
        uses: actions/checkout@v4
      - name: Create .env file
        run: <span class="hljs-built_in">echo</span> <span class="hljs-string">"PORT=<span class="hljs-variable">${{ secrets.PORT }</span>}"</span> &gt;&gt; .env
      - name: Login to docker hub
        run: sudo docker login -u <span class="hljs-variable">${{ secrets.DOCKER_USERNAME }</span>} -p <span class="hljs-variable">${{ secrets.DOCKER_PASSWORD }</span>}
      - name: Build docker image
        run: sudo docker build -t dhruvnakum/anonymous-go .
      - name: Push image to docker hub
        run: sudo docker push dhruvnakum/anonymous-go:latest
  deploy:
    needs: build
    runs-on: self-hosted
    steps:
      - name: Delete old anonymous-go container
        run: sudo docker rm -f anonymous-go  
      - name: Pull new anonymous-go docker image
        run: sudo docker pull dhruvnakum/anonymous-go
      - name: Delete old mongo container
        run: sudo docker rm -f mongo-demo
      - name: Pull new mongo docker image
        run: sudo docker pull mongo:8.0
      - name: Delete old network
        run: sudo docker network rm anonymous-go-nw
      - name: Create networks
        run: sudo docker network create anonymous-go-nw
      - name: Run mongo container
        run: sudo docker run --name mongo-demo --network anonymous-go-nw -d mongo:8.0
      - name: Run docker container
        run: |
          sudo docker run --name anonymous-go \
          --network anonymous-go-nw \
          -p 3000:3000 \
          -e MONGODB_URI=<span class="hljs-string">"mongodb://mongo-demo:27017"</span> \
          -e JWT_SECRET=<span class="hljs-string">"secret"</span> \
          -e REDIS_SECRET=<span class="hljs-string">"secret"</span> \
          -e REDIS_ADDR=<span class="hljs-string">"redis-11068.c261.us-east-1-4.ec2.redns.redis-cloud.com:11068"</span> \
          -e REDIS_PASSWORD=<span class="hljs-string">"DM4iBq2pTYNQkweBZmwqGKyDYrj872M8"</span> \
          -e PORT=3000 \
          -d dhruvnakum/anonymous-go:latest
</code></pre>
<p>Let me explain what's happening here:</p>
<ul>
<li><p>First, we named the workflow <code>Deploy to Go Application</code>.</p>
</li>
<li><p>To be safe, I created a new branch called <code>ec2</code> and pushed all the code to it. We want the workflow to run automatically whenever this branch is updated. Here's how we do it:</p>
</li>
</ul>
<pre><code class="lang-bash">on:
  push:
    branches: 
      - ec2
</code></pre>
<ul>
<li><p>We have two jobs: <strong>Build and Deploy</strong>.</p>
</li>
<li><p>In the <strong>Build job</strong>, we download our project's code, build a Docker image from it, and push it to Docker Hub.</p>
</li>
<li><p>In the <strong>Deploy job</strong>, we pull the Docker image of our project and the Mongo image from Docker Hub, run them inside one container as we did before, and finally, we run that container.</p>
</li>
</ul>
<hr />
<h2 id="heading-build-job">Build Job</h2>
<ul>
<li>We want this job to run on the latest Ubuntu operating system.</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">jobs</span>:
  build:
    runs-on: ubuntu-latest
</code></pre>
<ul>
<li>Now we want to download our project’s code from GitHub inside this OS, so we write this:</li>
</ul>
<pre><code class="lang-bash">name: Checkout <span class="hljs-built_in">source</span> code
uses: actions/checkout@v2
</code></pre>
<ul>
<li>Since we have environment variables in our code, we need to make them available here. To do this, we must add these secrets in <code>GitHub Action Secrets</code>. Go to the project's settings, and under secrets and variables, add these secrets.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739515733028/3ca76d47-72ef-4a61-a07a-620022310337.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Now, to get this from there, we create .env inside this OS and push everything:</li>
</ul>
<pre><code class="lang-bash">- name: Create .env file
  run: <span class="hljs-built_in">echo</span> <span class="hljs-string">"PORT=<span class="hljs-variable">${{ secrets.PORT }</span>}"</span> &gt;&gt; .env
</code></pre>
<ul>
<li>Now that we have all the secrets. We Login to the docker:</li>
</ul>
<pre><code class="lang-bash">- name: Login to docker hub
  run: sudo docker login -u <span class="hljs-variable">${{ secrets.DOCKER_USERNAME }</span>} -p <span class="hljs-variable">${{ secrets.DOCKER_PASSWORD }</span>}
</code></pre>
<ul>
<li>Then we build the docker image of our project:</li>
</ul>
<pre><code class="lang-bash">- name: Build docker image
  run: sudo docker build -t dhruvnakum/anonymous-go .
</code></pre>
<ul>
<li>Finally, we push the image to the docker hub:</li>
</ul>
<pre><code class="lang-bash">- name: Push image to docker hub
  run: sudo docker push dhruvnakum/anonymous-go:latest
</code></pre>
<hr />
<h2 id="heading-deploy-job">Deploy Job</h2>
<ul>
<li><p>In this job, everything we write will run on the AWS EC2 instance provided by GitHub.</p>
</li>
<li><p>We want this job to start after the build job finishes successfully.</p>
</li>
</ul>
<pre><code class="lang-bash">deploy:
    needs: build
</code></pre>
<ul>
<li>In this job, we first want to delete all the old containers and pull the latest ones. Once that is done, we run the container using <code>docker run</code> command.</li>
</ul>
<pre><code class="lang-bash">deploy:
    needs: build
    runs-on: self-hosted
    steps:
      - name: Delete old anonymous-go container
        run: sudo docker rm -f anonymous-go  
      - name: Pull new anonymous-go docker image
        run: sudo docker pull dhruvnakum/anonymous-go
      - name: Delete old mongo container
        run: sudo docker rm -f mongo-demo
      - name: Pull new mongo docker image
        run: sudo docker pull mongo:8.0
      - name: Delete old network
        run: sudo docker network rm anonymous-go-nw
      - name: Create networks
        run: sudo docker network create anonymous-go-nw
      - name: Run mongo container
        run: sudo docker run --name mongo-demo --network anonymous-go-nw -d mongo:8.0
      - name: Run docker container
        run: |
          sudo docker run --name anonymous-go \
          --network anonymous-go-nw \
          -p 3000:3000 \
          -e MONGODB_URI=<span class="hljs-string">"mongodb://mongo-demo:27017"</span> \
          -e JWT_SECRET=<span class="hljs-string">"secret"</span> \
          -e REDIS_SECRET=<span class="hljs-string">"secret"</span> \
          -e REDIS_ADDR=<span class="hljs-string">"redis-11068.c261.us-east-1-4.ec2.redns.redis-cloud.com:11068"</span> \
          -e REDIS_PASSWORD=<span class="hljs-string">"DM4iBq2pTYNQkweBZmwqGKyDYrj872M8"</span> \
          -e PORT=3000 \
          -d dhruvnakum/anonymous-go:latest
</code></pre>
<blockquote>
<p>Before we move ahead I forgot to change the URL in the main from localhost to <code>0.0.0.0</code> . So make sure you have this inside main.go at the end.</p>
<pre><code class="lang-bash">log.Fatal(r.Run(<span class="hljs-string">"0.0.0.0:"</span> + os.Getenv(<span class="hljs-string">"PORT"</span>)))
</code></pre>
</blockquote>
<hr />
<h1 id="heading-setting-up-aws-ec2-instance">Setting Up AWS EC2 Instance</h1>
<ul>
<li><p>Before deploying the project, we need to set up an EC2 instance.</p>
</li>
<li><p>To do this, log in to the AWS Management Console and go to the EC2 dashboard.</p>
</li>
<li><p>Use this link: <a target="_blank" href="https://aws.amazon.com/ec2/">https://aws.amazon.com/ec2/</a></p>
</li>
<li><p>It might ask for your card details, but don't worry; they won't charge you unless you exceed the limit, which you won't be charged for for this purpose.</p>
</li>
<li><p>Search for EC2 and click on it.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576315008/4743aac7-5276-4ada-a4b2-839861719665.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Now click on the “Launch Instance.”</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576363008/886edd48-54f3-46df-a3bc-77e9eb6e3708.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Now, give the instance name and select the Ubuntu image</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576476093/51e24e8e-7158-4890-a481-ef8162406067.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Also, select Key pair. If you don’t have one. You can create it by clicking on the Create new key pair button.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576528760/9a33561f-da16-4cc2-9fb9-ef9558b87978.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Once it is done, click on the Launch Instance button on the right</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576587591/5d1b7476-7395-4aa4-a996-e05561354490.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Since our app is running on port 3000, go to the Security Group settings and allow inbound traffic on <strong>port 3000</strong> to make sure the application is accessible.</p>
</li>
<li><p>To do that, click on the Instance ID</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576672455/daa31b8d-6768-4e61-a14b-1cd1dd729f85.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Then click on the Security tab and there click on Security Group</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576717820/dcbadb45-e7d2-4430-8284-5c4c19204800.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Click on Edit inbound rules and then add custom TCP with Port range 3000 as shown below and save the rules.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576774337/ad884b6d-df63-41f7-b114-81c37a401cd0.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Now, we are ready to run the instance.</li>
</ul>
<h2 id="heading-setting-up-docker-inside-ec2-instance">Setting up Docker inside EC2 Instance,</h2>
<ul>
<li>Our instance is ready. First, we need to make sure Docker is installed. To do this, let's connect to the instance. Click the Connect button after selecting the instance.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576897708/00324931-7359-47cf-afe2-00d882b64f6b.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Once you do that you will see a window like this:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739576982747/bcad9c57-c111-40ec-9f73-ee94ceef7df2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>To confirm whether docker is there or not, run <code>docker</code> command, you will most likely see this:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739577088622/017a2ea5-fbdc-4f14-9666-b58a9cca731c.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Now, to install everything, run the below commands</p>
</li>
</ul>
<pre><code class="lang-bash">sudo apt-get update &amp;&amp; sudo apt-get install docker.io -y &amp;&amp; sudo systemct| start docker &amp;&amp; sudo chmod 666 /var/run/docker.sock &amp;&amp; sudo systemcti <span class="hljs-built_in">enable</span> docker &amp;&amp; docker --version
</code></pre>
<ul>
<li>Once it is done, run <code>docker version</code> to see if it’s installed correctly.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739577318335/0482a21a-55c0-4d7d-ad5c-4adc5b558c26.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-register-a-self-hosted-github-runner">Register a Self-Hosted GitHub Runner</h2>
<ul>
<li><p>A <strong>self-hosted runner</strong> is simply a computer or server that you own (like an AWS EC2 instance) that runs GitHub Actions instead of using GitHub’s default machines.</p>
</li>
<li><p>To set up, go to the project settings, and inside Actions, you will see this runner tab.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739577522960/083333ac-9bc5-421d-81ee-16df3bada386.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Click on `New self-hosted runner:</p>
</li>
<li><p>Select Linux</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739577617221/1caf496c-c9d8-42c4-bfc4-32efc7d84a73.png" alt class="image--center mx-auto" /></p>
<ul>
<li>And run all the commands you see there inside your EC2.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739577640356/6ca70f3e-e61a-47ab-8c98-8a301644664a.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Once you run the last step <code>./run.sh</code> command, you will see a runner with the status idle :</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739577761453/8e1d7651-a258-447e-aab8-4101d725c6f9.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>But there is one problem, that runner does not run on detached mode in our instance, If you kill it by pressing CTRL+C, you wont be able to run it.</p>
</li>
<li><p>To resolve this issue, just run the below command</p>
</li>
</ul>
<pre><code class="lang-bash">sudo ./svc.sh install
</code></pre>
<pre><code class="lang-bash">sudo ./svc.sh start
</code></pre>
<ul>
<li><p>Now, your running is running in the background, and you can perform other operations inside your instance.</p>
</li>
<li><p>Finally, we are done with it. Now, we can test our application.</p>
</li>
</ul>
<h2 id="heading-testing-your-application">Testing Your Application</h2>
<ul>
<li>To test, commit to the <code>ec2</code> branch that we created. Once you do that, Go to the Actions tab, and there you will see both <code>build</code> <code>deploy</code> services are running.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739578220374/e8282b00-49f0-4118-8ad2-6bbb86a45e2b.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Once it is done, you will see both marked as green ticks, which means that everything went well and the docker is successfully up inside the ec2.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739578520776/9dd5ade3-30fb-404d-b77e-5e92968dc2e0.png" alt class="image--center mx-auto" /></p>
<ul>
<li>To test, go to the instance we created and find the <code>Public IPv4 address</code>. Copy it, paste it into Postman, and run any endpoint in your application.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739578733192/af6db6bd-4ce9-49ee-8b9d-8ad0c739dd4d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739578557983/130f27ee-5289-43a1-9a3c-3a0da8e237f3.png" alt class="image--center mx-auto" /></p>
<ul>
<li>As you can see it’s working now.</li>
</ul>
<p><img src="https://media1.tenor.com/m/sTbvauq7zVoAAAAC/lest-celebrate-happy.gif" alt="a man is sitting at a table with his arms outstretched in front of a crowd with the words let 's celebrate !!" class="image--center mx-auto" /></p>
<ul>
<li>Phew! I know that seems like a lot at first. But once you follow these steps, you'll get comfortable with it.</li>
</ul>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li><p>If you've made it to the end of this guide, you truly deserve a big thank you. So, thank you for sticking with it and reading all the way through. I hope you've gained a lot of valuable insights from this single blog post, covering everything from creating a GitHub Workflow to understanding Actions, setting up a Runner, and working with AWS EC2.</p>
</li>
<li><p>Keep diving deeper into these topics and explore other related concepts, as they are essential for cloud development in today's fast-paced tech world. Mastering these skills will undoubtedly enhance your ability to build and deploy applications efficiently.</p>
</li>
<li><p>I look forward to sharing more knowledge with you in the next blog post! Until then, keep learning and experimenting with new technologies.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<p>Reference: <a target="_blank" href="https://www.youtube.com/watch?v=sSAWMr_-Co4&amp;t=409s">https://www.youtube.com/watch?v=sSAWMr_-Co4&amp;t=409s</a></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a><strong>,</strong> <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a><strong>, and</strong> <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a><strong>.</strong></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Building Scalable GO Application With Docker, AWS, and GitHub Actions]]></title><description><![CDATA[Introduction

Hey, Gophers! I hope you're doing well. I'm back with Part 2 of the series. In the last blog, we learned about Docker and how it makes development easier with Containers.

We also created two containers: MongoDB and Redis.

Now that we ...]]></description><link>https://dhruvnakum.xyz/building-scalable-go-application-with-docker-aws-and-github-actions-1</link><guid isPermaLink="true">https://dhruvnakum.xyz/building-scalable-go-application-with-docker-aws-and-github-actions-1</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Docker]]></category><category><![CDATA[backend]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Tue, 11 Feb 2025 23:19:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739315332499/5184e511-e38c-474c-9686-9c87207e7201.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Hey, Gophers! I hope you're doing well. I'm back with Part 2 of the series. In the last blog, we learned about Docker and how it makes development easier with Containers.</p>
</li>
<li><p>We also created two containers: MongoDB and Redis.</p>
</li>
<li><p>Now that we have both running in Docker containers, it's time to build a custom image for a Go application. In this part, we'll learn about the Dockerfile, docker-compose file, and how to dockerize the application. By the end of this tutorial, you'll have a fully functional dockerized application that you can pull onto your machine and use without installing any dependencies.</p>
</li>
<li><p>Before that, I'll give you a quick overview of the project. I won't go into too much detail to keep the blog short. I'll just explain what the project is about, and then we'll get started with the main part. Let's do that!</p>
</li>
</ul>
<hr />
<h1 id="heading-project-overview">Project Overview</h1>
<ul>
<li><p>This is a simple project, but using all this tech together will be really fun. The project is about making a post anonymously, kind of like a tiny version of Reddit. It's just for learning, so it's okay if it's not very big. We'll only ask for a username and password, nothing else. The user signs up and logs in with these two things.</p>
</li>
<li><p>Users can create posts, and they can also like and comment on other people's posts.</p>
</li>
<li><p>Here's the mind map of what we'll use in our Go app and which APIs we'll implement.</p>
</li>
<li><p>By the way, the project's name is Anonymous-GO.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738898724300/90d28497-ede8-440c-a152-40865608c9d0.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Note: This blog requires basic knowledge of Go and how to work with APIs. I won't explain everything from the beginning. If you want to start from the basics, I already have a series on that. You might want to check it out first:</p>
<p><a target="_blank" href="https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-1">https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-1</a></p>
</blockquote>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/red-star25/anonymous-go">https://github.com/red-star25/anonymous-go</a></div>
<p> </p>
<ul>
<li>Here is the final project if you want to go through.</li>
</ul>
<hr />
<h1 id="heading-setting-up-go-project">Setting Up Go Project</h1>
<h2 id="heading-project-structure">Project Structure</h2>
<ul>
<li>We will structure our project as follows:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738900037978/7fe247f7-c226-405c-9598-149e1dbd945f.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>In <code>config/</code>, we have functions for setting up Redis.</p>
</li>
<li><p><code>controllers/</code> contains all the main operations like auth, post, like, and comment. This is where we define all the route handlers.</p>
</li>
<li><p>In <code>database/</code>, we set up MongoDB and have the User and Post collections.</p>
</li>
<li><p>In <code>middleware/</code>, we define handlers for accessing private routes.</p>
</li>
<li><p>In <code>models/</code>, we define different models like User, Post, Comment, and Like.</p>
</li>
<li><p>In <code>utils/</code>, we have helper functions for JWT authentication, and for hashing and verifying passwords.</p>
</li>
<li><p>We also have the <code>.env</code> file for storing all the project secrets.</p>
</li>
<li><p>We will discuss <code>docker-compose.yml</code>, <code>Dockerfile</code>, and <code>Dockerfile.dev</code> in the next section.</p>
</li>
</ul>
<hr />
<h1 id="heading-running-mongodb-containers">Running MongoDB Containers</h1>
<ul>
<li><p>If you read the previous blog, you might have a MongoDB container ready inside your docker. Let’s first run that.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738902307655/cd5057af-91ae-4857-8658-d593cc163da4.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<hr />
<ul>
<li><p>Before we start, we will use a MongoDB container for database storage and Redis Cloud for caching.</p>
</li>
<li><p>To run the project, we first need to start the MongoDB container to connect the database with the application.</p>
</li>
<li><p>When you run the project, you will see that both MongoDB and Redis are connected.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739135965979/a48a335f-c077-4c62-b7a0-55647a884dbf.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Let’s now dockerize this application.</p>
</li>
</ul>
<hr />
<h1 id="heading-dockerize-go-application">Dockerize GO Application</h1>
<ul>
<li>Before we start, let’s recap things we learned about Docker in our previous blog.</li>
</ul>
<h3 id="heading-what-is-docker-image"><strong>What is Docker Image?</strong></h3>
<ul>
<li><p>As we saw in our previous blog, Docker Image is a package/bundle that is used as a template to create <strong>containers.</strong></p>
</li>
<li><p>It contains everything needed to run an application. The docker image contains the application code. In our case, it is our Go code.</p>
</li>
<li><p>It also contains dependencies that we use in our application, like any libraries, frameworks, etc.</p>
</li>
<li><p>Contains all the tools and settings.</p>
</li>
<li><p>But the thing is Docker image cannot run on its own. As it’s just a template. To run the Image, we need to create a Container, just like Class and Object, Class is nothing without an Object, right!?</p>
</li>
</ul>
<h3 id="heading-what-is-docker-container"><strong>What is Docker Container?</strong></h3>
<ul>
<li><p>As Docker Image cannot run on its own, it requires Containers. Containers are basically running instances of a Docker Image.</p>
</li>
<li><p>You can think Docker Image as <code>Class</code> and Docker Containers as <code>Objects</code>. Class is nothing but a template and we can make use of class by creating it’s objects.</p>
</li>
<li><p>Every containers run in its isolated environment. And this containers runs exactly the same on every machine. Whether it’s Windows, Mac, or Linux.</p>
</li>
<li><p>As you can create multiple objects from a defined class. You can create multiple containers from the same image.</p>
</li>
</ul>
<hr />
<ul>
<li><p>Now you might be asking that, Okay, I understand Image and Containers now. But how do we create an Image of our application right?</p>
</li>
<li><p>Well that’s where Dockerfile comes into picture.</p>
</li>
</ul>
<h2 id="heading-dockerfile">Dockerfile</h2>
<ul>
<li><p>A Dockerfile is nothing but a set of instructions that tells Docker how to build a Docker Image.</p>
</li>
<li><p>Let’s see how we can write a docker file</p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> golang:<span class="hljs-number">1.23</span>-alpine AS builder
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> go.mod go.sum ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> go mod download</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> CGO_ENABLED=0 GOOS=linux go build -o main .</span>

<span class="hljs-keyword">FROM</span> alpine:latest
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /app/main /main</span>
<span class="hljs-keyword">COPY</span><span class="bash"> .env .</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"/main"</span>]</span>
</code></pre>
<ul>
<li><p>Let’s understand what’s happening here</p>
</li>
<li><p>First of all, we want Docker to compile our application, right? How do we do that? Well, Docker Hub already has the docker compiler image for us. It has all the tools, like <code>go build</code> <code>go mod</code>, etc.</p>
</li>
<li><p>So, we are using this docker image as our base. You might ask why we are using this image only and not the other one. The simple answer to that is it’s lightweight.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739145821608/206eed13-67d3-45ba-9557-54174436eb34.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> golang:<span class="hljs-number">1.23</span>-alpine
</code></pre>
<ul>
<li><p>The line above does that task. We also added <code>AS builder</code> after it. This simply labels this stage as "builder," so we can refer to it later.</p>
</li>
<li><p>You might ask why we need <code>builder</code> a stage.</p>
<ul>
<li><p>Well, we don’t want the final application to have every Go tool. It’s unnecessary. So, instead of storing unnecessary files in the final image, we directly build the app in this stage and then copy only the final compiled binary file into a new lightweight image.</p>
</li>
<li><p>This keeps the docker image small, fast, and secure.</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
</code></pre>
<ul>
<li><p>Here, we are creating a working directory inside the container. So, when we say <code>/app</code>, this means we are creating an app folder inside the container.</p>
</li>
<li><p>You might ask why we are creating app directory, can’t we just push all the things directly. Well, you can, but it’s not recommended. Why? Because If we don’t do this, every time we need to execute <code>cd</code> command manually to go inside <code>/app</code> folder</p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">COPY</span><span class="bash"> go.mod go.sum ./</span>
</code></pre>
<ul>
<li><p>The <code>COPY</code> instruction is used to copy the files from your <strong>local machine</strong> to <strong>docker containers.</strong></p>
</li>
<li><p>It will copy it inside <code>/app</code> as we previously set the current working directory as <code>/app</code></p>
</li>
<li><p>You might ask why we are copying this. well, otherwise, our application won’t run. These files contain all the dependencies required by our application.</p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">RUN</span><span class="bash"> go mod download</span>
</code></pre>
<ul>
<li>This command is used to download and cache all dependencies specified in <code>go.mod</code></li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
</code></pre>
<ul>
<li><p>Now that we are done with the basic setup, we need to copy all the files and folders of our application into a docker container.</p>
</li>
<li><p>The . (dot) here refers to the current directory on your local system and second . (dot) refers to the current working directory inside the container.</p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">RUN</span><span class="bash"> CGO_ENABLED=0 GOOS=linux go build -o main .</span>
</code></pre>
<ul>
<li><p>Now that we have copied our files, folders, and dependencies, we are ready to compile the application inside the container. This is what the above <code>RUN</code> instruction does.</p>
</li>
<li><p><code>go build -o main .</code> tells Go to <strong>compile the application</strong> and generate an <strong>executable file</strong> named <code>main</code>.</p>
</li>
<li><p>The <code>.</code> at the end means <strong>compiling all Go files in the current directory</strong> (<code>/app</code>). which is <code>main.go</code> in this case.</p>
</li>
<li><p>CGO allows Go programs to use C libraries, but it also makes the binary dependent on system libraries. And we don’t want that, so we are disabling it by assigning <code>0</code> value.</p>
</li>
<li><p>GOOS=linux is used to build the application for <strong>Linux</strong>. As we are using Alpine Linux image, we need to do that to make it lightweight for the system.</p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> alpine:latest
</code></pre>
<ul>
<li><p>Now that we have compiled the Go application in the previous <code>builder</code> stage. We now need to run the final binary which is created inside container.</p>
</li>
<li><p>To do that, we are using <code>alpine</code> container to create a lightweight container. This removes all the unnecessary libraries and tools.</p>
</li>
<li><p>In the previous stage (<code>golang:1.23-alpine AS builder</code>), we <strong>compiled the Go application</strong>.</p>
</li>
<li><p>Now, we only need to <strong>run the final binary</strong>, so we switch to a clean, minimal image.</p>
</li>
</ul>
<p>So what exactly happens here:</p>
<ul>
<li><p>Docker starts with a <strong>fresh Alpine Linux image</strong>.</p>
</li>
<li><p>No Go compiler or extra tools are installed, just a clean OS.</p>
</li>
<li><p>The final container only contains what's needed to run the application.</p>
</li>
</ul>
<p>Why Not Just Use <code>golang:1.23-alpine</code> for Everything?</p>
<ul>
<li>That’s a good question. It’s because The Go compiler and tools are only needed for building/compiling the app, not for running it. Keeping them in the final image wastes space and increases security risks. Using Alpine separately ensures a much smaller, optimized final container.</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /app/main /main</span>
</code></pre>
<ul>
<li><p>This line copies the compiled Go application from the <code>builder</code> stage into the final Alpine-based image.</p>
</li>
<li><p><code>/app/main</code> this is where the Go binary was built in the builder stage</p>
</li>
<li><p>And <code>/main</code> this is the destination inside the Alpine container</p>
</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>
</code></pre>
<ul>
<li>With this instruction, we are telling Docker that this container is expecting traffic at port 3000.</li>
</ul>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"/main"</span>]</span>
</code></pre>
<ul>
<li><p><code>ENTRYPOINT ["/main"]</code> tells Docker to <strong>execute the compiled Go binary</strong> (<code>/main</code>) inside the container.</p>
</li>
<li><p>So now, when you run the container, it automatically <strong>runs the</strong> <code>/main</code> binary.</p>
</li>
</ul>
<hr />
<h3 id="heading-how-does-this-overall-process-work">How does this overall process work?</h3>
<p><strong>First Stage (</strong><code>builder</code>)</p>
<ul>
<li><p>Uses <code>golang:1.23-alpine</code></p>
</li>
<li><p>Builds the <strong>Go application (</strong><code>main</code>) inside <code>/app</code></p>
</li>
<li><p>This stage has all the necessary tools (Go compiler, dependencies)</p>
</li>
</ul>
<p><strong>Final Stage (</strong><code>alpine:latest</code>)</p>
<ul>
<li><p>Starts with a <strong>clean Alpine Linux image</strong></p>
</li>
<li><p><strong>Copies only the</strong> <code>main</code> binary from <code>/app/main</code> into <code>/main</code></p>
</li>
<li><p>The container is now <strong>ready to run the application</strong></p>
</li>
</ul>
<hr />
<h3 id="heading-does-that-mean-we-are-using-two-containers">Does that mean we are using two Containers?</h3>
<ul>
<li><p><strong>No</strong>, we are <strong>not</strong> creating two containers. Instead, we are creating <strong>two separate environments during the build process</strong></p>
</li>
<li><p>Docker <strong>processes both stages</strong> during the <strong>image build</strong> phase.</p>
</li>
<li><p>It <strong>uses the first stage</strong> (<code>builder</code>) to compile the application.</p>
</li>
<li><p>It then <strong>discards the first stage</strong> and only <strong>keeps the final image</strong> from the second stage.</p>
</li>
<li><p>The <strong>container is created from this final, lightweight image</strong>.</p>
</li>
</ul>
<hr />
<h1 id="heading-docker-compose">docker-compose</h1>
<ul>
<li>Now our <code>Dockerfile</code> is ready. But right now, our app is only containerized. Remember, we are also using a <strong>MongoDB</strong> image in our app. If you try to run the app right now, it will throw an error because the app <strong>cannot connect to MongoDB</strong>.</li>
</ul>
<h2 id="heading-why-do-we-need-docker-composeyml">Why Do We Need <code>docker-compose.yml</code>?</h2>
<ul>
<li><p>Our <strong>app and MongoDB are running in separate containers</strong>.</p>
</li>
<li><p>The app <strong>depends on MongoDB</strong> to function, but without a shared network, they cannot communicate.</p>
</li>
<li><p>Running both services manually using <code>docker run</code> commands is inefficient.</p>
</li>
<li><p>This is where <strong>Docker Compose</strong> comes into play.</p>
</li>
<li><p>Docker Compose allows us to <strong>define and run multiple containers as a single service</strong>, ensuring that all required services (our app and MongoDB) start together, communicate seamlessly, and work as a unit.</p>
</li>
<li><p>With a <code>docker-compose.yml</code> file, we can:</p>
<ul>
<li><p><strong>Define multiple services</strong> (e.g., <code>app</code> and <code>mongo</code>) in a single configuration.</p>
</li>
<li><p><strong>Ensure MongoDB starts before the app</strong> using <code>depends_on</code>.</p>
</li>
<li><p><strong>Use a shared network</strong> so the app can communicate with MongoDB by referring to it as <code>mongo</code> instead of <a target="_blank" href="http://localhost"><code>localhost</code></a>.</p>
</li>
<li><p><strong>Set up environment variables</strong> for both services.</p>
</li>
<li><p><strong>Use volumes to persist MongoDB data</strong>, preventing data loss when containers restart.</p>
</li>
</ul>
</li>
<li><p>Now let’s write docker-compose for our app:</p>
</li>
</ul>
<pre><code class="lang-dockerfile">services:
  app:
    build:
      context: .
    ports:
      - <span class="hljs-string">"3000:3000"</span>
    depends_on:
      - mongo
    environment:
      - MONGODB_URI=mongodb://admin:admin@mongo:<span class="hljs-number">27017</span>/
      - JWT_SECRET=secret
      - REDIS_SECRET=secret
      - REDIS_ADDR=redis-<span class="hljs-number">11068</span>.c261.us-east-<span class="hljs-number">1</span>-<span class="hljs-number">4</span>.ec2.redns.redis-cloud.com:<span class="hljs-number">11068</span>
      - REDIS_USERNAME=default
      - REDIS_PASSWORD=DM4iBq2pTYNQkweBZmwqGKyDYrj872M8

  mongo:
    image: mongo:<span class="hljs-number">8.0</span>
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: admin
    ports:
      - <span class="hljs-string">"27017:27017"</span>
    volumes:
      - mongodata:/data/db

volumes:
  mongodata:
    driver: local
</code></pre>
<ul>
<li><p>So, as we know, we need two services: <strong>app</strong> and <strong>Mongo</strong></p>
</li>
<li><p>And that’s why we are defining those inside <code>services</code></p>
</li>
</ul>
<ol>
<li><p><code>app</code> Service:</p>
<ul>
<li><p>This service is used to build the app using <code>Docekerfile</code>.</p>
</li>
<li><p>So, we are defining its context with the current directory by specifying . (dot).</p>
</li>
<li><p>Then, we want to map the container port to the local system’s port (called port mapping). We do that inside <code>port</code> tag.</p>
</li>
<li><p>Also, we want mongo-db to run before our app starts. To achieve that, we have to use <code>depends_on</code> tag and specify <code>mongo</code> image.</p>
</li>
<li><p>Also, if you look at the project, we have specified many environmental variables. And so we want this app service to use that. So, we specify all the environment variables inside <code>ennvironment</code> tag.</p>
</li>
</ul>
</li>
<li><p><code>mongo</code> Service:</p>
<ul>
<li><p>We first need to pull up the Mongo image. We are doing it by specifying it inside the image tag.</p>
</li>
<li><p>As we did in our app, we are specifying env variables inside the environment tag.</p>
</li>
<li><p>Then, we need to expose port 27017 for database access.</p>
</li>
<li><p>Also, we want to keep the data in a persistent volume. So, we are using volumes</p>
</li>
</ul>
</li>
</ol>
<hr />
<h1 id="heading-running-docker-compose">Running docker-compose</h1>
<ul>
<li>Now that we are done with the <code>docker-compose</code> file, we can now run the container using the following command.</li>
</ul>
<pre><code class="lang-bash">docker compose up -d
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313199863/d034dcf1-1661-4cc9-8b93-d18e44716573.png" alt class="image--center mx-auto" /></p>
<ul>
<li>It will start the container inside the docker.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313229207/7701e00c-c1d0-4976-ab92-5a621a063237.png" alt class="image--center mx-auto" /></p>
<p><img src="https://media.tenor.com/gRAe8dfvrKMAAAAM/television-tv-shows.gif" alt="a man with a mustache in a blue suit says tiny celebration in front of a group of people" class="image--center mx-auto" /></p>
<ul>
<li><p>As you can see, our entire application is now dockerized.</p>
</li>
<li><p>Now, let’s test our API to see if it’s working or not.</p>
</li>
<li><p>Let’s create a user with a signup API</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313584476/1bf032bb-1c0b-4d91-a781-0c81f991a2c4.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Now, let’s test the login functionality with Redis caching.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313661204/5d48a2df-ed6e-4583-86c3-f868fb450301.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313672723/94f1b903-6474-4dda-a4ec-053c8d2b45d5.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>As you can see, Redis-session is added to cookies for accessing private routes. Let’s also test private routes to make sure they're working.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313781567/d7c9a3ab-1f81-41f8-ab0d-1fe951c0f5fe.png" alt class="image--center mx-auto" /></p>
<p>  And yes, it is working. And now, if you try to access private routes after logging out. It will not work. Let’s check that.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313819152/ea79e366-ab33-48ff-aadb-2d3af8bad306.png" alt class="image--center mx-auto" /></p>
<p>  - We logged out.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739313888578/a3c04d94-effb-44c5-a7d4-edd2f56bd279.png" alt class="image--center mx-auto" /></p>
<p>  As you can see, it’s throwing an error.</p>
</li>
</ul>
<hr />
<h1 id="heading-whats-next">What’s Next?</h1>
<ul>
<li><p>Currently, our APIs are working locally. But we want developers to use these APIs, right? To do that, we need to deploy this.</p>
</li>
<li><p>Now, there are many deployment options available in the market.</p>
</li>
<li><p>The most popular one is AWS.</p>
</li>
<li><p>In the next part, we are going to push our custom image to Docker Hub, set up GitHub actions, and Upload and Run this docker container inside the AWS EC2 instance.</p>
</li>
<li><p>It’s gonna be really good learning for anyone who is not familiar with AWS deployment. Because I learned a lot.</p>
</li>
<li><p>Let’s meet in the next one, until then…</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Building Scalable GO Application With Docker, AWS, and GitHub Actions]]></title><description><![CDATA[Introduction

Hey, Gophers! Thanks for stopping by and taking the time to read my blog. If you’ve been following my previous blogs, you might know that I recently started writing about Go. In my last article, we explored JWT authentication using the ...]]></description><link>https://dhruvnakum.xyz/building-scalable-go-application-with-docker-aws-and-github-actions</link><guid isPermaLink="true">https://dhruvnakum.xyz/building-scalable-go-application-with-docker-aws-and-github-actions</guid><category><![CDATA[Go Language]]></category><category><![CDATA[backend]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Fri, 07 Feb 2025 21:11:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738807715646/e6db401e-5c94-4fa0-a4bb-dc06130106d9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Hey, Gophers! Thanks for stopping by and taking the time to read my blog. If you’ve been following my previous blogs, you might know that I recently started writing about Go. In my last article, we explored JWT authentication using the JWT and Fiber packages in Go.</p>
</li>
<li><p>After covering the basics, I learned more advanced topics, such as working with databases, handling cookies and sessions, deploying Go applications on the cloud, using Docker, containerizing Go applications, etc.</p>
</li>
<li><p>And to put all these concepts into practice, I built a project that combined them all. Honestly, it was quite a challenge since AWS, Dockerization, Redis, and GitHub Actions were new to me. But after overcoming everything, I’m excited to share everything I’ve learned with you.</p>
</li>
<li><p>In this series, I’ll break down each concept in a simple and easy-to-understand way. If anything is unclear, feel free to ask in the comments!</p>
</li>
<li><p>By the end of this series, you’ll have a fully deployed, containerized project running in the cloud. If you're a beginner, this project will be a great addition to your resume, as we’ll be implementing many industry standard practices used in real-world applications.</p>
</li>
<li><p>We first need to learn a very important concept/tool called <strong>Docker.</strong> Because nowadays everyone is using it.</p>
</li>
<li><p>So, let’s first start with Docker and understand what Docker is. Why do we and people in the software industry use it? And What problem does it resolve?</p>
</li>
</ul>
<hr />
<h1 id="heading-why-do-we-need-docker">Why do we need Docker?</h1>
<ul>
<li><p>Before diving into what Docker is, let's first understand the issues it helps to resolve.</p>
</li>
<li><p>Imagine an organization with hundreds of developers, each working on different machines with different operating systems and configurations. Now, consider a project where a team of 50 developers is collaborating on the same GitHub repository.</p>
</li>
<li><p>As the team grows, new developers are hired and provided with new systems to work on. To get started, they need to clone the project from the repository and set up the development environment. Let's take two developers as an example:</p>
<ul>
<li><p><strong>Developer 1</strong> – A current employee who has already set up the project environment.</p>
</li>
<li><p><strong>Developer 2</strong> – A new employee who has just joined and needs to set up the project from scratch.</p>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738801055565/de5f91c4-4db7-47fb-a97c-16f2bd089dcd.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Developer 1</strong>, who has been working on the project from the beginning, has already set up all the necessary environments. Since this is a Go project, he runs the server locally using the following versions of key dependencies:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738801665997/268d347b-357d-439c-ab9a-7f1048fc92ba.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Now, the real challenge begins when <strong>Developer 2</strong> (a new employee) joins the team and needs to run the project on his system.</p>
<h4 id="heading-challenges-faced-by-the-new-developer">Challenges Faced by the New Developer</h4>
<ol>
<li><p><strong>Manual Setup Hassle</strong></p>
<ul>
<li><p>The new developer first clones the project from the repository.</p>
</li>
<li><p>He then needs to install multiple dependencies manually (Go, MongoDB, Redis, etc.).</p>
</li>
<li><p>In real-world projects, there are even more dependencies to install, making the setup tedious and error-prone.</p>
</li>
</ul>
</li>
<li><p><strong>Operating System Differences</strong></p>
<ul>
<li><p>Developer 1 might be using <strong>Windows</strong>, while Developer 2 has a <strong>Mac</strong>.</p>
</li>
<li><p>Some project commands may work on Windows but not on Mac.</p>
</li>
<li><p>Certain OS-specific compatibility issues might arise during the setup.</p>
</li>
</ul>
</li>
<li><p><strong>Version Mismatches</strong></p>
<ul>
<li><p>Developer 2 might install the latest versions of dependencies, which could be <strong>incompatible</strong> with the project.</p>
</li>
<li><p>Some dependencies may have breaking changes, causing unexpected issues.</p>
</li>
</ul>
</li>
<li><p><strong>Cloud Deployment Challenges</strong></p>
<ul>
<li><p>Eventually, the project will need to be deployed on the <strong>Cloud</strong>.</p>
</li>
<li><p>The cloud server might have a different environment, requiring another round of installations and conflict resolution.</p>
</li>
<li><p>Even after setting everything up, there’s no guarantee that the project will work as expected.</p>
</li>
</ul>
</li>
<li><p><strong>Scalability Issues</strong></p>
<ul>
<li><p>Today, it’s just one new developer-facing these challenges, but as the team grows, the setup process will have to be repeated for every new team member.</p>
</li>
<li><p>Constant communication and troubleshooting with each developer become inefficient and time-consuming.</p>
</li>
</ul>
</li>
</ol>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738801835525/36f07888-4daf-4230-99e4-d0732b620a10.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>This is where <strong>Docker</strong> comes into play. It provides a way to package the entire environment, ensuring that everyone (developers and cloud servers) runs the same setup without manual installations or version mismatches.</p>
</li>
<li><p>In the next section, we’ll dive into <strong>what Docker is, why it is useful, and how it solves these problems</strong>.</p>
</li>
</ul>
<hr />
<h1 id="heading-how-does-docker-resolve-this-problem">How does Docker resolve this problem?</h1>
<h2 id="heading-docker-container">Docker Container</h2>
<ul>
<li><p><strong>Docker is a platform</strong> that allows developers to create, deploy, and run applications inside <strong>containers</strong>.</p>
</li>
<li><p>What is <strong>a Container?</strong></p>
<ul>
<li>You can think of a <strong>container</strong> as a <strong>box</strong> that holds everything needed to run an application: its code, runtime, dependencies (like Go, MongoDB, Redis), and any required configurations.</li>
</ul>
</li>
<li><p>With Docker, we can create a <strong>container</strong> that includes all the necessary tools, packages, and dependencies. This container ensures that:</p>
<ul>
<li><p>Every developer gets the <strong>exact same versions</strong> of Go, MongoDB, Redis, and other dependencies.</p>
</li>
<li><p>The application runs <strong>identically on every system.</strong></p>
</li>
<li><p>The container is <strong>lightweight</strong>, meaning it doesn’t take up unnecessary resources like a full virtual machine would.</p>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738804258230/afb417c8-8d1d-4214-b825-d3c33a1b5b04.png" alt class="image--center mx-auto" /></p>
<ul>
<li>As you can see, this resolves the very big issue of installing and setting up the project environment again and again, and we can save our developers from the manual errors that they can make, as seen above.</li>
</ul>
<blockquote>
<p>To conclude, With Docker, we don’t have to install things like MongoDB or Redis manually again and again. Instead, we can run them inside containers and start using them instantly!</p>
</blockquote>
<ul>
<li>Okay, so now that we understand containers, there is one more term that we need to understand, which is Images.</li>
</ul>
<hr />
<h1 id="heading-docker-images">Docker Images</h1>
<ul>
<li><p>A <strong>Docker image</strong> is like a <strong>recipe</strong> that contains all the necessary ingredients and instructions to prepare a dish. However, instead of food, a <strong>Docker image</strong> contains everything needed to set up and run a software application.</p>
<h2 id="heading-understanding-docker-images-with-an-example">Understanding Docker Images with an Example</h2>
<ul>
<li><p>Imagine you have a laptop. Without an <strong>operating system</strong> (Windows, Mac, or Linux), your laptop is just a piece of hardware that can’t do much. Similarly, a <strong>Docker container</strong> needs a <strong>Docker image</strong> to function.</p>
</li>
<li><p>Think of a <strong>Docker image</strong> as the <strong>"operating system"</strong> for a container. It includes:</p>
<ul>
<li><p>The <strong>application code</strong></p>
</li>
<li><p>All the <strong>dependencies</strong> (like Go, MongoDB, Redis, etc.)</p>
</li>
<li><p>The <strong>runtime environment</strong></p>
</li>
<li><p>Any necessary <strong>configurations</strong></p>
</li>
</ul>
</li>
<li><p>Once a Docker image is created, it serves as a <strong>blueprint</strong> to generate multiple <strong>containers</strong>. Each container runs independently but follows the same instructions defined in the image, just like you can cook the same dish multiple times using the same recipe.</p>
</li>
<li><p>With Docker images, developers can ensure consistency across different environments, making application deployment seamless and reliable.</p>
</li>
</ul>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738807602410/ce121aa0-db24-4bcb-8aef-cf146af4bf34.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>I hope everything is clear now.</p>
</li>
<li><p>If not, then don’t worry; we are now going to do some hands-on exercises and see everything that we have learned so far in action.</p>
</li>
</ul>
<hr />
<h1 id="heading-docker-installation">Docker Installation</h1>
<h2 id="heading-docker-desktop">Docker Desktop</h2>
<ul>
<li><p>To run <strong>Docker containers</strong> on your machine, you need to install the <strong>Docker Desktop</strong> application.</p>
<p>  You can download it from the official website:</p>
</li>
<li><p><a target="_blank" href="https://www.docker.com/">Docker Desktop Installation</a></p>
</li>
<li><p>Or simply search <strong>“Docker Desktop install”</strong> online, and it will take you to the installation page.</p>
</li>
<li><p><strong>Docker Desktop</strong> is a <strong>GUI (Graphical User Interface)</strong> that makes it easy to:</p>
<ul>
<li><p>Manage <strong>containers</strong></p>
</li>
<li><p>View and control <strong>Docker images</strong></p>
</li>
<li><p>Monitor <strong>volumes</strong> and <strong>networks</strong></p>
</li>
<li><p>Configure <strong>Docker settings</strong></p>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738886863347/3504b267-b621-430f-a1b8-8f572ebaa961.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>It provides a user-friendly way to interact with Docker without using only command-line tools, making container management more accessible.</p>
</li>
<li><p>Once you are done with the installation, open the terminal of your choice and run <code>docker</code> command</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738887424428/741f9615-ccda-49c0-839e-6a0953f4d2bd.png" alt class="image--center mx-auto" /></p>
<ul>
<li>It should show a similar result. This tells us that docker is successfully installed in our system. You can also verify using.</li>
</ul>
<pre><code class="lang-go">docker --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738887737906/3e9037d6-d66d-4620-b8f5-3da748c9bc59.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Now open your Docker desktop.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738887841617/c17eafdf-db9b-4a44-8337-9f976f355ff3.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>If you open <strong>Docker Desktop</strong>, you’ll notice several sections on the left-hand side:</p>
<ul>
<li><p><strong>Containers</strong> – Shows running and stopped containers.</p>
</li>
<li><p><strong>Images</strong> – Lists downloaded and built Docker images.</p>
</li>
<li><p><strong>Volumes</strong> – Manages persistent data storage for containers.</p>
</li>
<li><p><strong>Builds</strong> – Tracks built images and processes.</p>
</li>
</ul>
</li>
<li><p>We've already covered <strong>Containers</strong> and <strong>Images</strong>, and that’s all we need to get started!</p>
</li>
<li><p>Okay, so for our upcoming project, we’ll need <strong>MongoDB</strong> and <strong>Redis</strong> as dependencies. Instead of <strong>manually installing</strong> them and setting up everything from scratch (which is boring and time-consuming 😩), we can use <strong>Docker</strong> to simplify the process.</p>
</li>
<li><p>With Docker, we can:</p>
<ul>
<li><p>Pull <strong>pre-built images</strong> of MongoDB and Redis.</p>
</li>
<li><p>Run them as <strong>containers</strong>.</p>
</li>
<li><p>Avoid dependency conflicts or setup issues.</p>
</li>
</ul>
</li>
<li><p>This means <strong>no more frustrating installations</strong>, we just run a command, and everything works!</p>
</li>
<li><p>Before that, let’s understand what Docker hub is.</p>
</li>
</ul>
<hr />
<h1 id="heading-docker-hub">Docker Hub</h1>
<ul>
<li>You might be wondering when I say we need to pull Docker images for MongoDB and Redis, where these images actually come from. It comes from Docker Hub. Docker hub is similar to Github but for docker images.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738888750254/59ef5588-7192-4735-934c-9de49613bc84.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>It’s an online repository where developers can find and share Docker images.</p>
</li>
<li><p>You can also create your custom image on your system and push it to the docker hub for others to use. We are going to create a custom image for our Go application and push it to the docker hub in the future.</p>
</li>
<li><p>What we, as developers, have to do is just pull these images using the command <code>docker pull</code>, and we are all set.</p>
</li>
</ul>
<hr />
<h1 id="heading-running-mongodb-in-a-docker-container">Running MongoDB in a Docker Container</h1>
<ul>
<li>Instead of manually installing MongoDB, we can use <strong>Docker</strong> to set it up in seconds with the following command:</li>
</ul>
<pre><code class="lang-powershell">docker run <span class="hljs-literal">-d</span> -<span class="hljs-literal">-name</span> mongo<span class="hljs-literal">-demo</span> \
<span class="hljs-literal">-e</span> MONGO_INITDB_ROOT_USERNAME=admin \
<span class="hljs-literal">-e</span> MONGO_INITDB_ROOT_PASSWORD=admin \
<span class="hljs-literal">-p</span> <span class="hljs-number">27017</span>:<span class="hljs-number">27017</span>
mongo:<span class="hljs-number">8.0</span>
</code></pre>
<ul>
<li><p>Let’s understand this command:</p>
<ul>
<li><p><code>docker run -d</code> : It runs this container in a detached mode. This means that if we do not provide this tag, our terminal will be in use, and we won’t be able to perform any other operations. So, we need to run this container in the background</p>
</li>
<li><p><code>—name mongo-demo</code> : We are naming our container as ‘mongo-demo’</p>
</li>
<li><p>Now, for security purposes, we are setting the Username and Password for our database using <code>-e MONGO_INITDB_ROOT_USERNAME</code> and <code>-e MONGO_INITDB_ROOT_PASSWORD</code></p>
</li>
<li><p>We are also mentioning the <code>port</code> We want Mongo to run locally in our system.</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<h2 id="heading-port-mapping">PORT MAPPING</h2>
<ul>
<li><p>When we run MongoDB inside a <strong>Docker container</strong>, it operates in an <strong>isolated environment</strong>. This means it <strong>does not</strong>automatically connect to our <strong>local machine</strong>.</p>
</li>
<li><p>If we try to access MongoDB <strong>from outside the container</strong>, it won’t work unless we <strong>explicitly expose its port</strong>.</p>
</li>
<li><p>This is where <strong>Port Mapping</strong> comes in!</p>
</li>
</ul>
<p>Here, <code>-p 27017:27017</code> means:</p>
<ul>
<li><p>The first <code>27017</code> (before the <code>:</code>) is the <strong>port on your local machine</strong> (host).</p>
</li>
<li><p>The second <code>27017</code> (after the <code>:</code>) is the <strong>port inside the container</strong>.</p>
</li>
</ul>
<p>By default, services running <strong>inside a Docker container</strong> are <strong>not accessible</strong> from outside.</p>
<ul>
<li><p>MongoDB <strong>inside the container</strong> is running on <strong>port 27017</strong>.</p>
</li>
<li><p>But our system (local machine) <strong>doesn’t know that</strong> unless we explicitly expose it.</p>
</li>
<li><p>By mapping <strong>MongoDB’s internal port (27017) to our system’s port (27017)</strong>, we make it accessible.</p>
</li>
</ul>
</blockquote>
<ul>
<li><p>At the end, we are specifying which image to pull, and that is <code>mongo:8.0</code></p>
</li>
<li><p>If you search Mongo in the docker hub, you will find its image shown below.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738889210463/8878f7c9-0c9e-437e-9b42-d01f65d206ec.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<ul>
<li><p>What that above command will do is :</p>
<ul>
<li><p>Pulls the <strong>MongoDB 8.0 image</strong> from Docker Hub (if not already downloaded).</p>
</li>
<li><p>Starts a <strong>MongoDB container</strong> with a <strong>default admin username and password</strong>.</p>
</li>
<li><p>Allows us to interact with MongoDB just like we would on a locally installed version, but without the manual setup!</p>
</li>
</ul>
</li>
<li><p>Once it is done, you will see this container running in your Docker Desktop.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738889497178/c0d717fa-f141-42ac-98bd-4451c91cece9.png" alt class="image--center mx-auto" /></p>
<ul>
<li>To check if it’s running or not, you can run the below command</li>
</ul>
<pre><code class="lang-powershell">docker <span class="hljs-built_in">ps</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738889831317/34e37744-3aee-40ea-8aef-5fe88d886c3d.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>This will list all the running containers</p>
</li>
<li><p>Now, let’s run the Redis container</p>
</li>
</ul>
<hr />
<h1 id="heading-running-redis-in-docker-container">Running Redis in Docker Container</h1>
<ul>
<li>Just like MongoDB, we can set up <strong>Redis</strong> instantly using Docker without manually installing anything. Use the following command:</li>
</ul>
<pre><code class="lang-powershell">docker run <span class="hljs-literal">-d</span> -<span class="hljs-literal">-name</span> redis<span class="hljs-literal">-demo</span> redis:latest
</code></pre>
<ul>
<li><p>This will pull the <strong>latest Redis image</strong> (if not already available locally) and then start a <strong>Redis container</strong> that runs in the background.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738891888914/8ac8bb10-b5fd-4226-9d10-4b364b736d3c.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Again, to verify whether it’s running or not, let’s run <code>docker ps</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738891941701/b5bcb82f-23d4-47ba-84c4-34e9e87d3ea4.png" alt class="image--center mx-auto" /></p>
<ul>
<li>As you can see, our Mongo and Redis containers are working pretty well.</li>
</ul>
<blockquote>
<p>Now that we have <strong>MongoDB and Redis running inside containers</strong>, we don’t need to install them manually on our system. Anytime we need them, we can just <strong>start the containers</strong>, and everything will work instantly.</p>
</blockquote>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li>With Docker, we’ve reduced the hassle of manual installations and ensured a <strong>consistent</strong> and <strong>error-free</strong> development environment. No more dependency issues or version conflicts, just a simple setup in seconds!</li>
</ul>
<hr />
<h1 id="heading-whats-next">What’s Next?</h1>
<ul>
<li><p>This blog serves as the <strong>foundation</strong> for the next steps in our series. Now that you understand docker and how it works. We are ready to containerize our Go application.</p>
</li>
<li><p>Stay tuned for the next part! 🚀 Until then.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a><strong>,</strong> <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a><strong>, and</strong> <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a><strong>.</strong></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Step-by-Step Guide to Secure Authentication in Go using JWT and Fiber]]></title><description><![CDATA[Introduction

After the last series on Go, I've been learning some new ideas, like Secure Authentication. I discovered JWT authentication and how it helps secure routes.

In this article, I'll explain how we can use JWT to authenticate users and secu...]]></description><link>https://dhruvnakum.xyz/step-by-step-guide-to-secure-authentication-in-go-using-jwt-and-fiber</link><guid isPermaLink="true">https://dhruvnakum.xyz/step-by-step-guide-to-secure-authentication-in-go-using-jwt-and-fiber</guid><category><![CDATA[Go Language]]></category><category><![CDATA[APIs]]></category><category><![CDATA[backend]]></category><category><![CDATA[JWT]]></category><category><![CDATA[authentication]]></category><category><![CDATA[development]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Wed, 15 Jan 2025 20:48:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736973584310/9933a1fc-6b91-4919-97b3-8cfb6e2ec3a0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>After the last series on Go, I've been learning some new ideas, like Secure Authentication. I discovered JWT authentication and how it helps secure routes.</p>
</li>
<li><p>In this article, I'll explain how we can use JWT to authenticate users and secure routes.</p>
</li>
<li><p>So, let's jump right in.</p>
</li>
</ul>
<hr />
<h1 id="heading-creating-a-base-folder-structure">Creating a Base Folder Structure</h1>
<ul>
<li><p>We'll start by setting up a project structure to clearly see how everything fits together.</p>
</li>
<li><p>First, create a directory and open your favorite code editor. I prefer VS Code.</p>
</li>
</ul>
<pre><code class="lang-bash">bmkdir go-auth
<span class="hljs-built_in">cd</span> go-auth
code .
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736891030948/06a8af76-f508-4a1f-9e37-31fce7059cf4.png" alt class="image--center mx-auto" /></p>
<ul>
<li>So this is our project structure :</li>
</ul>
<p><strong>cmd/server/main.go</strong></p>
<ul>
<li>This is the entry point of the application</li>
</ul>
<p><strong>controllers/auth_controller.go</strong></p>
<ul>
<li>This is where we place our controllers/handlers. In our case, it will be <strong>auth_controller</strong>. Here we will implement all the functions related to authentication like Register, Login, and Logout.</li>
</ul>
<p><strong>database/db.go</strong></p>
<ul>
<li>In this database, setup is done and the connection is made. We will be using <strong>MySQL</strong> as our database.</li>
</ul>
<p><strong>middleware/middleware.go</strong></p>
<ul>
<li>Middleware is simply a function that wraps around our HTTP handlers to add extra features. For example, once a user is logged in, we use middleware to secure other routes like /dashboard and /cart. We will learn about middleware in this blog.</li>
</ul>
<p><strong>models/user.go</strong></p>
<ul>
<li>The model represents the data structure of the application’s data. So for example, if you are building an application related to a library, models can be, a book, author, etc. In this project which we are building, we need <code>user</code> a model as we are dealing with the user’s authentication.</li>
</ul>
<p><strong>routes/routes.go</strong></p>
<ul>
<li>We define all the HTTP routes here. We are using <code>fiber</code> a package for managing the application routes. If you are familiar with express in Node.js then this package is inspired by it and provides flexible ways and functionalities to manage routes.</li>
</ul>
<p><strong>types/types.go</strong></p>
<ul>
<li>In this, we define our own custom struct types which we require in our application.</li>
</ul>
<p><strong>.env</strong></p>
<ul>
<li>This is an environmental file where we put all the secure stuff.</li>
</ul>
<hr />
<h1 id="heading-load-env-file">Load <code>.env</code> File</h1>
<ul>
<li><p>First of all, let’s load all the environmental variables in our application.</p>
</li>
<li><p>For that, we are using a package called <code>gotdotenv</code>. This helps us achieve this.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get github.com/joho/godotenv
</code></pre>
<ul>
<li>Let’s load this env file inside our application. Go to <code>main.go</code> and paste below code</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"github.com/joho/godotenv"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    err := godotenv.Load()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(<span class="hljs-string">"Error loading .env file"</span>)
    }
}
</code></pre>
<ul>
<li>We place it at the top of the main function because we need all the variables loaded before the server starts.</li>
</ul>
<hr />
<h1 id="heading-connect-database">Connect Database</h1>
<ul>
<li><p>We are using MySQL to work with the database. I was going through some queries and everything as It’s been a while since I wrote any. And then I came across the term ORM (Object-Relation Mapping). And I found it super convenient as we can use objects oriented approach to execute the queries.</p>
</li>
<li><p>So an <strong>ORM</strong> is a programming technique that allows us to interact with a relational database like MySQL using object-oriented programming principles, instead of writing raw SQL queries. It serves as a bridge between the object-oriented language and the database, mapping database tables to objects in the application.</p>
</li>
<li><p>And researching more about it I found this package called <code>gorm</code> for Go. So we will be using this to work with our database.</p>
</li>
<li><p>Let’s install it and also we need to install the mysql driver for it separately.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get -u gorm.io/gorm
<span class="hljs-keyword">go</span> get gorm.io/driver/mysql
</code></pre>
<ul>
<li>Let’s now create <code>Connect</code> function and write the logic to connect our application with the database.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> database

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"os"</span>

    <span class="hljs-string">"gorm.io/driver/mysql"</span>
    <span class="hljs-string">"gorm.io/gorm"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Connect</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    dsn := fmt.Sprintf(<span class="hljs-string">"%s:%s@tcp(127.0.0.1:3306)/go_auth?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"</span>, os.Getenv(<span class="hljs-string">"DB_USERNAME"</span>), os.Getenv(<span class="hljs-string">"DB_PASSWORD"</span>))
}
</code></pre>
<ul>
<li><p>Inside <code>Connect()</code> we first initilized <code>dsn</code> (Data Source Name). <code>dsn</code> is nothing but a string that provides all the information to connect the database. It includes information like database type, server location, username password, database name, etc.</p>
</li>
<li><p>Here we used <code>fmt.Sprintf</code> which returns a formatted string. We used two string <code>%s</code> placeholders for username and password. And we are getting those values from the <code>.env</code> file.</p>
</li>
<li><p>Let’s first add those values to our <code>.env</code></p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// .env</span>
DB_USERNAME=root
DB_PASSWORD=root123
</code></pre>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Connect</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    dsn := fmt.Sprintf(<span class="hljs-string">"%s:%s@tcp(127.0.0.1:3306)/go_auth?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"</span>, os.Getenv(<span class="hljs-string">"DB_USERNAME"</span>), os.Getenv(<span class="hljs-string">"DB_PASSWORD"</span>))
    db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }
}
</code></pre>
<ul>
<li><p>After that, we open the connection to the MySQL database using Gorm's <code>Open()</code> function. We use the <code>mysql</code> driver's <code>Open</code> function to connect with our <code>dsn</code> string. The second parameter is for gorm configuration if you have any.</p>
</li>
<li><p>This <code>gorm.Open</code> function returns two things: <code>db</code> instance and <code>error</code>. So what we need to do is, first we need to create a global <code>gorm.DB</code> variable that our application can use from anywhere inside the project.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> DB *gorm.DB

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Connect</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<ul>
<li>And that’s why we create <code>var DB *gorm.DB</code> .It’s a pointer because we need whatever changes we made in this variable, it reflects the original one which is <code>db</code> inside the <code>Connect</code> function.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Connect</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    dsn := fmt.Sprintf(<span class="hljs-string">"%s:%s@tcp(127.0.0.1:3306)/go_auth?charset=utf8mb4&amp;parseTime=True&amp;loc=Local"</span>, os.Getenv(<span class="hljs-string">"DB_USERNAME"</span>), os.Getenv(<span class="hljs-string">"DB_PASSWORD"</span>))
    db, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    log.Info(<span class="hljs-string">"Database connected successfully"</span>)
    DB = db

    db.AutoMigrate(&amp;models.User{})
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<ul>
<li><p>And that is why we assigned <code>db</code> to global <code>DB</code> variable.</p>
</li>
<li><p>Then we have this <code>db.AutoMigrate(&amp;User{})</code> function. What this AutoMirgrate function does is, it creates the same table with all the values defined inside this model <code>User</code> inside the database.</p>
</li>
<li><p>This means that GORM will ensure that the table corresponding to the <code>User</code> model in the database matches the structure defined in the model, creating or updating columns as necessary.</p>
</li>
<li><p>And so when you run the application for the first time, it will create a table for you automatically.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736931374997/8838aeb1-23a8-48ed-a0fb-11caa339f022.png" alt class="image--center mx-auto" /></p>
<ul>
<li>We haven’t created our User model yet so let’s create it first.</li>
</ul>
<hr />
<h1 id="heading-user-model">User Model</h1>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> models

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    Id       
    Name    
    Email    
    Password
}
</code></pre>
<ul>
<li>Here we’ve created a simple User struct, which contains basic information like ID, Name Email, and Password.</li>
</ul>
<hr />
<ul>
<li>Now that we have the database file ready we can use the Connect function inside our main function to connect the database.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    err := godotenv.Load()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(<span class="hljs-string">"Error loading .env file"</span>)
    }

    <span class="hljs-keyword">if</span> err = database.Connect(); err != <span class="hljs-literal">nil</span> {
        log.Fatalf(<span class="hljs-string">"Could not connect to the database, %v"</span>, err)
    }
}
</code></pre>
<ul>
<li>Now let’s run the project to see if it’s working</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> run cmd/server/main.<span class="hljs-keyword">go</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736895776659/89b1ca4e-edd0-445a-9f93-4883d4439220.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-setting-up-the-router">Setting Up the Router</h1>
<ul>
<li>Okay so for route management, as we discussed earlier we are using <code>fiber</code> package. To install run the following command inside your terminal</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get github.com/gofiber/fiber/v2
</code></pre>
<ul>
<li>Let’s create an instance of fiber inside <code>main.go</code> to use it inside our application</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">//...</span>

    app := fiber.New()
}
</code></pre>
<ul>
<li><p>Using this <code>app</code> we can now create our routes.</p>
</li>
<li><p>To make things look clean and separate we will implement all the routes inside <code>routes.go</code>.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// routes.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">SetupRoutes</span><span class="hljs-params">(app *fiber.App)</span></span> {
    app.Post(<span class="hljs-string">"/api/register"</span>, controllers.Register)
    app.Post(<span class="hljs-string">"/api/login"</span>, controllers.Login)
    app.Post(<span class="hljs-string">"/api/logout"</span>, controllers.Logout)
}
</code></pre>
<ul>
<li><p>Here we have created <code>SetupRoutes</code> a function that takes a <code>app</code> variable of type <code>*fiber.App</code>.</p>
</li>
<li><p>Inside this, we created three routes, <code>/register</code>, <code>login/</code> and <code>/logout</code>. (Don’t worry if you are seeing an error saying these functions are not found. We are going to implement them in a bit)</p>
</li>
<li><p>Now we call this function in <code>main.go</code> like this</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">//...</span>

    routes.SetupRoutes(app)
}
</code></pre>
<ul>
<li>Now let’s implement these handler functions inside controllers.</li>
</ul>
<hr />
<h1 id="heading-implementing-route-handlers">Implementing Route Handlers</h1>
<h2 id="heading-register">Register</h2>
<pre><code class="lang-go"><span class="hljs-comment">// controllers/auth_controller.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">var</span> regReq types.RegisterRequest
}
</code></pre>
<ul>
<li><p>Since we receive the submitted data in an HTTP request, we need to create a custom struct type to convert all that data into a format that Go can understand.</p>
</li>
<li><p>Let’s create a RegisterRequest struct for the Register handler</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// types/types.go</span>

<span class="hljs-keyword">type</span> RegisterRequest <span class="hljs-keyword">struct</span> {
    Name    
    Email   
    Password
}
</code></pre>
<ul>
<li>Let’s now parse the request body of the register to this type</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">var</span> regReq types.RegisterRequest

    <span class="hljs-keyword">if</span> err := c.BodyParser(&amp;regReq); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"invalid request format"</span>,
        })
    }
}
</code></pre>
<ul>
<li><p>Function <code>BodyParser</code> helps bind the body fields to a struct field. It returns an <code>error</code> of type <code>ErrUnprocessableEntity</code> which means if BodyParser fails to bind the fields it will throw this error.</p>
</li>
<li><p>So we handled it by returning an error message “invalid request format“ with a status code 500 (StatusInternalServerError)</p>
</li>
<li><p>Now before we create our user and send it to the database to store, we can’t just send the <code>password</code> as it is. We need to secure it by converting it into some hash or something.</p>
</li>
<li><p>Go has this package called <code>bcrypt</code> which helps us achieve that. First, let’s install the package</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get golang.org/x/crypto/bcrypt
</code></pre>
<ul>
<li><p><code>bcrypt</code> has a function <code>GenerateFromPassword</code> that takes a byte of <code>password</code> string as the first parameter and <code>cost</code> as the second parameter (<code>cost</code> determines the computational complexity of the hashing process. It is a measure of how long it takes to hash a password, directly affecting the time it takes to verify the hash later)</p>
</li>
<li><p>Let’s hash our password and then create a user object</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">//...</span>

    password, _ := bcrypt.GenerateFromPassword([]<span class="hljs-keyword">byte</span>(regReq.Password), <span class="hljs-number">10</span>)

    user := models.User{
        Name:     regReq.Name,
        Email:    regReq.Email,
        Password: password,
    }
}
</code></pre>
<ul>
<li><p>This bcrypt function returns two values: encrypted password and error.</p>
</li>
<li><p>And after that, we can construct our user model by using <code>regReq</code> struct and encrypted <code>password</code>.</p>
</li>
<li><p>Now before we send this to the database, we need to first check whether this user already exists in the database or not.</p>
</li>
</ul>
<pre><code class="lang-go">
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// ...   </span>

    database.DB.Where(<span class="hljs-string">"email = ?"</span>, user.Email).First(&amp;user)
}
</code></pre>
<ul>
<li><p>We can do this using the <code>Where</code> function of the MySQL database. Since each email is unique in our application, we wrote a query that returns a user if they exist.</p>
</li>
<li><p>Now we check if we found anything or not like this:</p>
</li>
</ul>
<pre><code class="lang-go">
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// ...   </span>

    database.DB.Where(<span class="hljs-string">"email = ?"</span>, user.Email).First(&amp;user)

    <span class="hljs-keyword">if</span> user.Id != <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> c.Status(fiber.StatusConflict).JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"user already exists"</span>,
        })
    }
}
</code></pre>
<ul>
<li><p>If <code>user.Id</code> is not <code>0</code>, it means we found a user, so we return an error message saying "user already exists."</p>
</li>
<li><p>If we didn't find anything, we create a new user in the database using the <code>Create()</code> function of <code>DB</code>.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// ...</span>

    database.DB.Create(&amp;user)
}
</code></pre>
<ul>
<li>And once everything is done, we send a message back to the API response saying "user created successfully" along with the user information.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Register</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">return</span> c.JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"user created successfully"</span>,
            <span class="hljs-string">"data"</span>:    user,
        })
}
</code></pre>
<ul>
<li>That was pretty straightforward, wasn’t it?</li>
</ul>
<h1 id="heading-running-the-server">Running the Server</h1>
<ul>
<li>To run the server, we use the <code>app</code>'s <code>Listen</code> function and specify the port number like this:</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// main.go</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">//...</span>

    log.Println(<span class="hljs-string">"Starting server at: "</span>, <span class="hljs-number">3000</span>)
    err = app.Listen(<span class="hljs-string">":3000"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatalln(<span class="hljs-string">"Error Starting Server at: "</span>, <span class="hljs-number">3000</span>)
    }
}
</code></pre>
<ul>
<li>Now let’s run the app</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736920984238/293f89d4-7edc-4ca8-94ce-205224c96e7e.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-login">Login</h2>
<pre><code class="lang-go"><span class="hljs-comment">// controllers/auth_controller.go</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Login</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">var</span> loginReq types.LoginRequest

    <span class="hljs-keyword">if</span> err := c.BodyParser(&amp;loginReq); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">if</span> err := validate.Struct(&amp;loginReq); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"Validation failed"</span>,
            <span class="hljs-string">"errors"</span>:  err.Error(),
        })
    }
}
</code></pre>
<ul>
<li>This part of the Login remains the same as the Register. We have created a LoginRequest structure inside <code>types.go</code></li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// types/types.go</span>

<span class="hljs-keyword">package</span> types

...

<span class="hljs-keyword">type</span> LoginRequest <span class="hljs-keyword">struct</span> {
    Email 
    Password
}
</code></pre>
<ul>
<li><p>Now, we need to check if the user exists in the database when the client tries to log in with their credentials.</p>
</li>
<li><p>To do this, we will use the <code>Where()</code> function of <code>DB</code> to see if the email is in the database. If it exists (we check this by seeing if <code>user.Id</code> is not <code>0</code>), we proceed with further operations otherwise, we return an error.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Login</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {    
     <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">var</span> user models.User

    database.DB.Where(<span class="hljs-string">"email = ?"</span>, loginReq.Email).First(&amp;user)

    <span class="hljs-keyword">if</span> user.Id == <span class="hljs-number">0</span> {
        c.Status(fiber.StatusNotFound)
        <span class="hljs-keyword">return</span> c.JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"user not found"</span>,
        })
    }
}
</code></pre>
<ul>
<li>If the user exists, we compare the incoming password with the one in the database. If they match, the credentials are correct. If they don't match, we return an error saying "incorrect password."</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Login</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {    
     <span class="hljs-comment">// ...</span>
     <span class="hljs-keyword">if</span> err := bcrypt.CompareHashAndPassword(user.Password, []<span class="hljs-keyword">byte</span>(loginReq.Password)); err != <span class="hljs-literal">nil</span> {
        c.Status(fiber.StatusBadRequest)
        <span class="hljs-keyword">return</span> c.JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"incorrect password"</span>,
        })
    }
}
</code></pre>
<ul>
<li><p><code>bcrypt</code> has a function called <code>CompareHashAndPassword</code> that checks the incoming password against the one stored in the database.</p>
</li>
<li><p>After that, we just send a JSON response with a success message and the data.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Login</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {    
     <span class="hljs-comment">// ...</span>
    <span class="hljs-keyword">return</span> c.JSON(fiber.Map{
        <span class="hljs-string">"message"</span>: <span class="hljs-string">"success"</span>,
        <span class="hljs-string">"data"</span>:    loginReq,
    })
}
</code></pre>
<ul>
<li>Let’s check the Login handler by running the project.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736921033382/81a139f4-7fca-448a-b056-24cbff67bc86.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-logout">Logout</h2>
<ul>
<li><p>The logout feature is very simple. On the backend, there's not much to do. The frontend should handle the logout process.</p>
</li>
<li><p>So, when this route is accessed, we just return a success message.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Logout</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {

    <span class="hljs-keyword">return</span> c.JSON(fiber.Map{
        <span class="hljs-string">"message"</span>: <span class="hljs-string">"Logged out successfully"</span>,
    })
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736920106216/9ba3f9b1-803b-443b-9f44-a5246f4ca2cd.png" alt class="image--center mx-auto" /></p>
<ul>
<li>One problem right now here is, that even if you aren’t logged in, you can still log out. And this issue we will resolve below by using JWT.</li>
</ul>
<hr />
<h1 id="heading-json-tags">JSON Tags</h1>
<ul>
<li>If you see the response of Login and Register…</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736921232447/a2098f0a-477a-4ca1-9a66-216cb61b47d5.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736921246555/a67e94b8-e1eb-4fe4-84f9-9bdafd0cb9d2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>We notice that the field names are not in lowercase. To convert these fields into a JSON-friendly format, we use what are called <strong>Tags</strong> in Go.</p>
</li>
<li><p>Tags specify how struct fields should be encoded into or decoded from JSON. So, even if we have a struct field like <code>Name</code>, we can encode and decode it as <code>name</code> using an annotation.</p>
</li>
<li><p>To achieve this, we need to make changes inside <code>types.go</code> and <code>user.go</code>.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// user.go</span>

<span class="hljs-keyword">package</span> models

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    Id       <span class="hljs-keyword">uint</span>   <span class="hljs-string">`json:"id"`</span>
    Name     <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"name"`</span>
    Email    <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"email" gorm:"unique"`</span>
    Password []<span class="hljs-keyword">byte</span> <span class="hljs-string">`json:"-"`</span>
}
</code></pre>
<ul>
<li><p>Here, we made the email a unique key in the database. This means the same email address can't be used again.</p>
</li>
<li><p>Another thing to note is that we added <code>-</code> in front of <code>Password</code> because we don't want this field to appear in the response for security reasons.</p>
</li>
<li><p>Now, let's modify <code>types.go</code>.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> types

<span class="hljs-keyword">type</span> RegisterRequest <span class="hljs-keyword">struct</span> {
    Name     <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"name"`</span>
    Email    <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"email"`</span>
    Password <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"password"`</span>
}

<span class="hljs-keyword">type</span> LoginRequest <span class="hljs-keyword">struct</span> {
    Email    <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"email"`</span>
    Password <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"password"`</span>
}
</code></pre>
<ul>
<li>Now if you run the project and see the response, it should be fixed</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736921680567/9a617c39-56bc-4048-9d37-20db3a10fe3f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736921709635/ff22bb8a-a347-46ee-8d21-e8985780cdfd.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-jwt-authentication">JWT Authentication</h1>
<ul>
<li>Let’s first understand what JWT is before we dive into code.</li>
</ul>
<h2 id="heading-what-is-jwt">What is JWT?</h2>
<ul>
<li><p>JWT (JSON Web Token) is a way to safely send data between the client and server.</p>
</li>
<li><p>It is a token made up of three main parts:</p>
<ul>
<li><p><strong>Header:</strong> This includes information like the signing method and type of token.</p>
</li>
<li><p><strong>Payload:</strong> This has Claims, which are details about the user data, such as user ID and expiration time.</p>
</li>
<li><p><strong>Signature:</strong> This is made by signing the header and payload with a secret or private key. It checks if the token is real.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-flow-of-jwt-authentication">Flow of JWT Authentication</h2>
<ul>
<li><p>The client sends credentials to the server.</p>
</li>
<li><p>If the credentials are valid, the server generates a JWT containing the user's information and signs it.</p>
</li>
<li><p>The server sends the JWT to the client, typically as part of the HTTP response.</p>
</li>
<li><p>The client stores the token (e.g., in local storage or an HTTP-only cookie).</p>
</li>
<li><p>The client includes the JWT in the <code>Authorization</code> header (ex, <code>Bearer &lt;token&gt;</code>).</p>
</li>
<li><p>The server validates the token’s signature and checks its claims (e.g., expiration time, roles).</p>
</li>
<li><p>If valid, the server processes the request; otherwise, it rejects it.</p>
</li>
</ul>
<h2 id="heading-implement-jwt-authentication">Implement JWT Authentication</h2>
<ul>
<li>To use JWT in our app, let’s first add the package</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get github.com/dgrijalva/jwt-<span class="hljs-keyword">go</span>/v4
</code></pre>
<ul>
<li>In our app, when a user logs in successfully, we create a JWT token. After checking the password, we start by creating a claim to build the token.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> err := bcrypt.CompareHashAndPassword(...); err != <span class="hljs-literal">nil</span> {<span class="hljs-comment">//...}</span>

claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
        Issuer: strconv.Itoa(<span class="hljs-keyword">int</span>(user.Id)),
        ExpiresAt: &amp;jwt.Time{
            Time: time.Now().Add(time.Hour * <span class="hljs-number">24</span>),
        },
    })
</code></pre>
<ul>
<li><p><code>jwt</code> provides a function called <code>NewWithClaims</code> to create a Claim. It takes two parameters:</p>
<ul>
<li><p><strong>Signing Method:</strong> We can choose from several secure hashing algorithms, but we are using HS256.</p>
</li>
<li><p><strong>Claim:</strong> We include the claims we mentioned earlier, like user ID and expiry time, using the <code>jwt.StandardClaims</code> interface. We set the user ID in <code>Issuer</code> as a string and <code>ExpiresAt</code> with a time value, set to 24 hours. This means the token will expire after 24 hours.</p>
</li>
<li><p>Now that we have the claims ready, we will create a token.</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-go">token, err := claims.SignedString([]<span class="hljs-keyword">byte</span>(os.Getenv(<span class="hljs-string">"JWT_SECRET"</span>)))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.Status(fiber.StatusInternalServerError)
        <span class="hljs-keyword">return</span> c.JSON(fiber.Map{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"could not log in"</span>,
        })
    }
</code></pre>
<ul>
<li>As you can see claims have a method named <code>SignedString</code> which we use to sign the JWT secret. We typically store the secret inside <code>.env</code> file.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// .env</span>

<span class="hljs-comment">// ... other keys</span>
JWT_SECRET=secret
</code></pre>
<ul>
<li><p>Use a strong secret key for better security. I have used <code>secret</code> for testing purposes.</p>
</li>
<li><p>And after everything’s done we get the token.</p>
</li>
<li><p>If you remember this line:</p>
</li>
</ul>
<p>“ A JWT token is simply a mix of signed claims and secret/private keys. I hope this explanation makes it clear.”</p>
<ul>
<li>And as mentioned in the <strong>Flow of JWT part</strong> we send this token to the client so that they can send it back to the backend to access secure/private routes</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// auth_controller.go</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Login</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">return</span> c.JSON(fiber.Map{
        <span class="hljs-string">"message"</span>: <span class="hljs-string">"success"</span>,
        <span class="hljs-string">"token"</span>:   token,
        <span class="hljs-string">"data"</span>:    loginReq,
    })

}
</code></pre>
<ul>
<li>Okay so, now that we created the JWT token. Whenever a user tries to access private routes, we need to first validate the user, whether he is logged in or not. To do that we create a middleware</li>
</ul>
<hr />
<h1 id="heading-middlewares">Middlewares</h1>
<ul>
<li><p>In Go, we create middleware that acts as a layer between the HTTP request and the handler that processes it.</p>
</li>
<li><p>Middleware is simply a function that takes an HTTP handler and returns an HTTP handler. In our app, we need middleware to ensure the user accessing the route is authorized to access private routes before entering.</p>
</li>
<li><p>To implement it, go to <code>middleware/middlewares.go</code> and paste the code below.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> middleware

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"os"</span>

    jwtware <span class="hljs-string">"github.com/gofiber/contrib/jwt"</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Protected</span><span class="hljs-params">()</span> <span class="hljs-title">fiber</span>.<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> jwtware.New(jwtware.Config{
        SigningKey: jwtware.SigningKey{
            JWTAlg: <span class="hljs-string">"HS256"</span>,
            Key:    []<span class="hljs-keyword">byte</span>(os.Getenv(<span class="hljs-string">"JWT_SECRET"</span>)),
        },
        TokenLookup:  <span class="hljs-string">"header:Authorization"</span>,
        AuthScheme:   <span class="hljs-string">"Bearer"</span>,
        ErrorHandler: jwtError,
    })
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">jwtError</span><span class="hljs-params">(c *fiber.Ctx, err error)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">return</span> c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
        <span class="hljs-string">"message"</span>: <span class="hljs-string">"Unauthorized"</span>,
    })
}
</code></pre>
<ul>
<li><p>Starting with imports, we are using <code>"github.com/gofiber/contrib/jwt"</code> packages and gave aliases as <code>jwtware</code>.</p>
</li>
<li><p>Here we have created a function <code>Protected()</code> that returns an HTTP handler. Inside this we are returning <code>jwtware.New()</code> handler which is used  to create a new middleware instance for validating JWT</p>
</li>
<li><p>Here we pass different keys:</p>
<ul>
<li><p>SigningKey: This specifies the algorithm and key for verifying JWT’s signature.</p>
</li>
<li><p>TokenLookup: Defines where the middleware should look for JWT</p>
</li>
<li><p>AuthScheme: It defines which scheme to use in <code>Authorization</code></p>
</li>
<li><p>ErrorHandler: It is a custom function to handle errors. So whenever an unauthorized user access any routes which require authorization, this throws an error message: “Unauthorized “</p>
</li>
</ul>
</li>
<li><p>In our case, we need two routes: Log in and Register as Public routes and Logout as Private route. How do we do that?</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// routes.go</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">SetupRoutes</span><span class="hljs-params">(app *fiber.App)</span></span> {
    <span class="hljs-comment">// Public routes</span>
    app.Post(<span class="hljs-string">"/api/register"</span>, controllers.Register)
    app.Post(<span class="hljs-string">"/api/login"</span>, controllers.Login)

    app.Use(middleware.Protected())

    <span class="hljs-comment">// Protected routes</span>
    app.Post(<span class="hljs-string">"/api/logout"</span>, controllers.Logout)
}
</code></pre>
<ul>
<li><p>As you can see, to use any middleware, fiber provides a very handy method called <code>Use()</code> . So what will happen now is whatever routes defined after <code>app.Use(middleware.Protected())</code> this will require a JWT Token to get access.</p>
</li>
<li><p>Let’s see it in action.</p>
</li>
</ul>
<ol>
<li><p>Open Postman</p>
</li>
<li><p>Try to logout directly</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736929382431/16d32da0-e63f-4720-b158-736f19cf49d8.png" alt class="image--center mx-auto" /></p>
<p>As you can see, Now it is throwing an error saying “Unauthorized“.</p>
<ol start="3">
<li><p>Now login with valid credentials</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736929416766/a3ac0569-311d-4ac7-a5f3-df92654c88b2.png" alt class="image--center mx-auto" /></p>
<p> Copy the token and paste it inside the Authorization Bearer field and then try to logout.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736929513628/c7f57d57-c17e-4f5a-aa5d-cdd106e002c9.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p><img src="https://media1.tenor.com/m/9PItHYqz9gwAAAAd/yay-moinyin.gif" alt="a group of minions are standing next to each other and one of them is saying yay ." class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-code">Code</h1>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/red-star25/jwt-auth-go">https://github.com/red-star25/jwt-auth-go</a></div>
<p> </p>
<hr />
<h1 id="heading-conclusion">Conclusion</h1>
<ul>
<li><p>In this article, we've explored how to implement secure user authentication in a Go application using JWTs and the Fiber framework.</p>
</li>
<li><p>We saw how to set up a project structure, connect to a MySQL database with GORM, and define essential routes and middleware.</p>
</li>
<li><p>We've built handlers for managing user registration, login, and protected routes. This approach not only enhances the security of your application but also provides a scalable framework for future development.</p>
</li>
<li><p>I hope you liked this article and learned something from it. If you did consider leaving a like and feedback in the comment section.</p>
</li>
<li><p>See you in the next one, until then….</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a><strong>,</strong> <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a><strong>, and</strong> <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a><strong>.</strong></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Zero to Go Hero: Learn Go Programming with Me - Part 5]]></title><description><![CDATA[Introduction

Welcome to the last part of this Learn Go Programming series. In the previous parts, we learned lots of new stuff about Go and saw how easy and fast it is to build a backend. In the last blog, we created a Read function for getting all ...]]></description><link>https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-5</link><guid isPermaLink="true">https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-5</guid><category><![CDATA[Go Language]]></category><category><![CDATA[backend]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Sat, 11 Jan 2025 23:15:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736490292529/1c56d7bd-8960-48bf-9724-52a3870d9d77.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Welcome to the last part of this Learn Go Programming series. In the previous parts, we learned lots of new stuff about Go and saw how easy and fast it is to build a backend. In the last blog, we created a Read function for getting all the books that are there in the database.</p>
</li>
<li><p>In this part, we are going to implement the remaining operations which are:</p>
<ul>
<li><p>Create Book</p>
</li>
<li><p>Update Book</p>
</li>
<li><p>Delete Book and</p>
</li>
<li><p>Get a Specific Book</p>
</li>
</ul>
</li>
<li><p>So let’s get started without wasting any more time.</p>
</li>
</ul>
<hr />
<h1 id="heading-create-a-book-post">Create a Book (POST)</h1>
<h2 id="heading-setting-up-the-route">Setting up the route</h2>
<ul>
<li><p>Now to create a book, first, let’s configure the route for it.</p>
</li>
<li><p>Go to <code>routes.go</code> and add a new handler called <code>CreateBookHandler</code></p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// routes.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">SetupRouter</span><span class="hljs-params">()</span> *<span class="hljs-title">chi</span>.<span class="hljs-title">Mux</span></span> {
    ...
    r.Post(<span class="hljs-string">"/book"</span>, books.CreateBookHandler) <span class="hljs-comment">// Yet to be created inside handler.go</span>
    ...
}
</code></pre>
<ul>
<li>As we need to create something inside the database, we need to use the POST method of HTTP.</li>
</ul>
<h2 id="heading-creating-a-handler">Creating a Handler</h2>
<ul>
<li>Head over to <code>handler.go</code> and paste the below code:</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// handler.go</span>

...
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">CreateBookHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    <span class="hljs-keyword">var</span> book Book
    err := json.NewDecoder(r.Body).Decode(&amp;book)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to decode book"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    err = CreateBook(book) <span class="hljs-comment">// Yet to be created inside service.go</span>
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to create book"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    w.WriteHeader(http.StatusCreated)
}
...
</code></pre>
<ul>
<li><p>So when we are creating something, we are most probably getting the data from the client side. In our case where we are creating a book, let’s say the admin wants to add a book to the website. What he will do is, add the details of the book in text fields on the front side and then press the Submit button.</p>
</li>
<li><p>So when he does that, all the data that were filled by the admin comes to the backend inside a request Body in a JSON format</p>
</li>
<li><p>So what we need to do here is, we just need to <code>decode</code> this data into our Go structure format.</p>
</li>
<li><p>For that, we used this <code>json.Decoder()</code> function which takes <code>json</code> string and then <code>Decode()</code> takes a struct in which we need to fill the converted data.</p>
</li>
<li><p>Then we need to call <code>CreateBook()</code> service of database which will add a new entry for the new book.</p>
</li>
<li><p>Let’s write this function inside <code>service.go</code></p>
</li>
</ul>
<h2 id="heading-creating-a-createbook-service">Creating a <code>CreateBook</code> Service</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">CreateBook</span><span class="hljs-params">(book Book)</span> <span class="hljs-title">error</span></span> {
    _, err := database.DB.Exec(<span class="hljs-string">"INSERT INTO books (title, author, year) VALUES (?, ?, ?)"</span>, book.Title, book.Author, book.Year)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<ul>
<li><p>In <code>service.go</code> file we need to create a function called <code>CreateBook</code>. This function takes a struct of type Book which we will pass from the handler. And it will return an error.</p>
</li>
<li><p>Inside the function, we are writing a create query for MySQL database. It’s self-explanatory so I am not going into details.</p>
</li>
<li><p>In the end, we are returning an error if anything goes wrong.</p>
</li>
<li><p>It was pretty simple, right?</p>
</li>
<li><p>Let’s run the project and test it inside Postman.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/i6Uhx99q4LY">https://youtu.be/i6Uhx99q4LY</a></div>
<p> </p>
<ul>
<li>I already created two books for testing before so you are also seeing those in output.</li>
</ul>
<hr />
<h1 id="heading-update-a-book-put">Update a Book (PUT)</h1>
<h2 id="heading-setting-up-the-route-1">Setting up the Route</h2>
<ul>
<li>Now that we have created a book. We can now create an Update functionality. Let’s go to the <code>routes.go</code> and create a PUT router</li>
</ul>
<pre><code class="lang-go">...
r.Put(<span class="hljs-string">"/book/{id}"</span>, books.UpdateBookHandler)
...
</code></pre>
<ul>
<li><p>We need an <code>id</code> to update a particular book, right? To do that we can use a unique identifier which is <code>id</code> for our book. So When the user/admin updates a particular book client sends the <code>id</code> of it with the request to our backend.</p>
</li>
<li><p>So if you see, after <code>/book/</code> we have <code>id</code> inside curly braces. This is a dynamic value. When a client hits a URL with this path like, <code>/book/1</code> or <code>/book/20</code>, we can get this book dynamic <code>id</code> and perform update operations.</p>
</li>
<li><p>Let’s now create <code>UpdateBook</code> handler function</p>
</li>
</ul>
<h2 id="heading-creating-a-handler-1">Creating a Handler</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">UpdateBookHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    id, err := strconv.Atoi(r.PathValue(<span class="hljs-string">"id"</span>))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to convert id"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-keyword">var</span> book Book
    err = json.NewDecoder(r.Body).Decode(&amp;book)

    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to decode book"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    err = UpdateBook(id, book)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to update book"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    w.WriteHeader(http.StatusOK)
}
</code></pre>
<ul>
<li><p>Okay so in the first line, we are getting <code>id</code> using request objects <code>PathValue</code> function. Here we pass the exact value that we passed inside the route which is <code>id</code>.</p>
</li>
<li><p>But we need to convert them <code>id</code> to <code>int</code> because our database accepts the ID of type integer.</p>
</li>
<li><p>For that, we are using <code>strconv</code> package. And it has <code>Atoi</code> (ASCII to Integer) function which takes a string and converts it to an integer. It also returns <code>err</code> if it isn’t able to convert. So we are handling that error too.</p>
</li>
<li><p>Then we decode the sent JSON data to our book struct.</p>
</li>
<li><p>In the end, we call the <code>UpdateBook</code> a function where we pass the <code>id</code> and <code>book</code> struct.</p>
</li>
<li><p>Let’s create a database service for Updating a book in the database.</p>
</li>
</ul>
<h2 id="heading-creating-a-updatebook-service">Creating a <code>UpdateBook</code> Service</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">UpdateBook</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>, book Book)</span> <span class="hljs-title">error</span></span> {
    _, err := database.DB.Exec(<span class="hljs-string">"UPDATE books SET title = ?, author = ?, year = ? WHERE id = ?"</span>, book.Title, book.Author, book.Year, id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<ul>
<li><p>Here we are just executing an update query.</p>
</li>
<li><p>Let’s run the project and see if it’s working.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/08qVfHK3yts">https://youtu.be/08qVfHK3yts</a></div>
<p> </p>
<hr />
<ul>
<li><p>Okay, so I changed my mind and thought to give you some exercise.</p>
</li>
<li><p>I want you to create <code>DELETE</code> a route for deleting a book. And <code>GET</code> route for getting “a single book“ from the database.</p>
</li>
<li><p>I will share the code with you but before that, I recommend trying it out on your own.</p>
</li>
<li><p>No cheating…</p>
</li>
</ul>
<hr />
<p>.</p>
<p>.</p>
<p>.</p>
<p>.</p>
<p>.</p>
<ul>
<li>You didn’t try, didn’t you…</li>
</ul>
<p><img src="https://media.tenor.com/Ab18aZakEuIAAAAM/dog-sussy.gif" alt="a small brown and white dog with a mustache on its face ." class="image--center mx-auto" /></p>
<hr />
<ul>
<li>Anyway here is the code..</li>
</ul>
<h1 id="heading-deleting-a-book">Deleting a Book</h1>
<pre><code class="lang-go"><span class="hljs-comment">// routes.go</span>
r.Delete(<span class="hljs-string">"/book/{id}"</span>, books.DeleteBookHandler)
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">// handler.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">DeleteBookHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    id, err := strconv.Atoi(r.PathValue(<span class="hljs-string">"id"</span>))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to convert id"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    err = DeleteBook(id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to delete book"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    w.WriteHeader(http.StatusOK)
}
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">//service.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">DeleteBook</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">error</span></span> {
    _, err := database.DB.Exec(<span class="hljs-string">"DELETE FROM books WHERE id = ?"</span>, id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/dNMDLiC5Wj0">https://youtu.be/dNMDLiC5Wj0</a></div>
<p> </p>
<hr />
<h1 id="heading-getting-book-by-id">Getting Book by <code>id</code></h1>
<pre><code class="lang-go"><span class="hljs-comment">// routes.go</span>
...
r.Get(<span class="hljs-string">"/book/{id}"</span>, books.GetBookHandler)
...
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">//handler.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetBookHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    id, err := strconv.Atoi(r.PathValue(<span class="hljs-string">"id"</span>))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to convert id"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    book, err := GetBook(id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to fetch book"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
    json.NewEncoder(w).Encode(book)
}
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">// service.go</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetBook</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-params">(Book, error)</span></span> {
    <span class="hljs-keyword">var</span> book Book
    err := database.DB.QueryRow(<span class="hljs-string">"SELECT id, title, author, year FROM books WHERE id = ?"</span>, id).Scan(&amp;book.ID, &amp;book.Title, &amp;book.Author, &amp;book.Year)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> book, err
    }
    <span class="hljs-keyword">return</span> book, <span class="hljs-literal">nil</span>
}
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/lfy6amgY5ho">https://youtu.be/lfy6amgY5ho</a></div>
<p> </p>
<hr />
<h1 id="heading-modifications">Modifications</h1>
<ul>
<li><p>We did finish our project but there are a few things that need to be fixed in this project. For example, When we are Updating a book, we must pass the whole object with every value instead of just a value that we need to update.</p>
</li>
<li><p>There are no clear messages in the console after we perform operations.</p>
</li>
<li><p>We should add proper logs inside each error-handling block.</p>
</li>
<li><p>I want you to do a little bit of research on these points and update the code.</p>
</li>
<li><p>It is pretty easy and I think with a little bit of research and work you will be able to complete it.</p>
</li>
</ul>
<hr />
<h1 id="heading-github-repository">GitHub Repository</h1>
<ul>
<li>Here is the Git repository that contains all the code.</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/red-star25/crud-api">https://github.com/red-star25/crud-api</a></div>
<p> </p>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li><p>That’s it. We have officially completed this series. I hope you learned something from this series.</p>
</li>
<li><p>If you have any queries or concerns regarding any concepts, please feel free to comment it. I’ll try to answer it as per my knowledge.</p>
</li>
<li><p>In future blogs, I am planning to experiment more with Golang and create new projects with it. So stay tuned and follow to get the notifications.</p>
</li>
<li><p>See you in the next one, until then…</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[From Zero to Go Hero: Learn Go Programming with Me - Part 4]]></title><description><![CDATA[Introduction

Heyy Gophers!!! Welcome to the Part 4 of Learning Go with Me. Thanks for coming alone to till here. I hope you are learning and enjoying this series.

Till now we almost covered the fundamentals of Go and now we are ready to write out t...]]></description><link>https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-4</link><guid isPermaLink="true">https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-4</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Developer]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[learning]]></category><category><![CDATA[development]]></category><category><![CDATA[backend]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Fri, 10 Jan 2025 21:03:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736228159917/fee94889-26b2-4966-80bb-cbdc14d95be9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Heyy Gophers!!! Welcome to the Part 4 of Learning Go with Me. Thanks for coming alone to till here. I hope you are learning and enjoying this series.</p>
</li>
<li><p>Till now we almost covered the fundamentals of Go and now we are ready to write out the first API.</p>
</li>
<li><p>It’s gonna be exciting as we will learn a lot of new things which will help you in your first programming career</p>
</li>
<li><p>Let’s get started without wasting any more time.</p>
</li>
</ul>
<hr />
<ul>
<li>We already have the project structure ready for us</li>
</ul>
<pre><code class="lang-plaintext">crud-api/
│
├── cmd/
│   └── main/
│       └── main.go           # Entry point for the application
│
├── config/
│   └── config.go             # Environment variable management
│
├── internal/
│   ├── routes/
│   │   └── routes.go         # API routes definition
│   ├── books/
│   │   ├── handler.go        # HTTP handlers for book operations
│   │   ├── model.go          # Book database model and queries
│   │   └── service.go        # Business logic for books
│   ├── database/
│   │   └── db.go             # Database connection logic
│
├── .env                      # Environment variables
├── go.mod                    # Go module dependencies
└── .gitignore                # Ignored files
</code></pre>
<ul>
<li>Also we have dependencies installed in our project from Part 1 of this series</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get github.com/<span class="hljs-keyword">go</span>-chi/chi/v5
<span class="hljs-keyword">go</span> get github.com/<span class="hljs-keyword">go</span>-sql-driver/mysql
<span class="hljs-keyword">go</span> get github.com/joho/godotenvfg
</code></pre>
<ul>
<li>And lastly, we have the environment file ready for us</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// .env</span>
PORT=<span class="hljs-number">8080</span>
DB_USER=root
DB_PASSWORD=password
DB_HOST=<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">3306</span>
DB_NAME=crud_api
</code></pre>
<ul>
<li><p>Now let’s go step by step. As we already have the .env file ready for us, why not create a function to load it inside our project?</p>
</li>
<li><p>Before that let’s see the main.go file</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// main.go</span>

<span class="hljs-keyword">package</span> main

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Load .env file</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Setup database connection</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Setup router</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Run server</span>
}
</code></pre>
<ul>
<li>These are our TODOs which we need to complete</li>
</ul>
<hr />
<h1 id="heading-loading-env-variables">Loading <code>.env</code> Variables</h1>
<ul>
<li><p>To load values inside our <code>.go</code> files we are using <code>godotenv</code> package. This package helps us get environmental values inside our file.</p>
</li>
<li><p>We implement this function inside <code>config.go</code> file. So head over to <code>config.go</code> and let’s write <code>LoadEnv</code> function. But before that let’s import a few packages</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// config/config.go</span>

<span class="hljs-keyword">package</span> config

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"os"</span>

    <span class="hljs-string">"github.com/joho/godotenv"</span>
)
</code></pre>
<ul>
<li>We are using <code>log</code>, <code>os</code> and <code>godotenv</code> packages here.</li>
</ul>
<hr />
<h2 id="heading-fmt-and-log-packages"><code>fmt</code> and <code>log</code> Packages</h2>
<ul>
<li><p>In Go we mostly use these two packages to print out values and logs in the terminal. At first, these two may look similar but they both serve different purposes.</p>
</li>
<li><p><code>log</code> is specifically designed for logging messages. This means we can get more information like time stamping and error reporting with this. So we mostly use it during application runtime like debugging, informational logs, and error logs.</p>
<ul>
<li>It includes functions like <code>log.Fatal</code>(Exists the program after logging) and <code>log.Panic</code> (Logs and then panic)</li>
</ul>
</li>
<li><p>Whereas <code>fmt</code> is used for general-purpose printing text. It is commonly used for printing in a console with formatted strings. So we use it mostly when we are printing user-facing messages.</p>
</li>
</ul>
<h3 id="heading-example">Example</h3>
<pre><code class="lang-go">fmt.Println(<span class="hljs-string">"Hello World"</span>) <span class="hljs-comment">// Hello World</span>
fmt.Printf(<span class="hljs-string">"Hello %s"</span>, <span class="hljs-string">"World"</span>) <span class="hljs-comment">// Hello World</span>

log.Fatalf(<span class="hljs-string">"This is a fatal error."</span>) <span class="hljs-comment">// This is a fatal error. (After this program stops)</span>
log.Panic(<span class="hljs-string">"This is a panic error."</span>) <span class="hljs-comment">// This is a panic error. (After this program stops)</span>
</code></pre>
<ul>
<li><p>More on <code>fmt</code> visit: <a target="_blank" href="https://pkg.go.dev/fmt">https://pkg.go.dev/fmt</a></p>
</li>
<li><p>More on <code>log</code> visit: <a target="_blank" href="https://pkg.go.dev/log">https://pkg.go.dev/log</a></p>
</li>
</ul>
<hr />
<h2 id="heading-os-package"><code>os</code> Package</h2>
<ul>
<li><p>The <code>os</code> package in Go is used for tasks related to the operating system. For example accessing the files, and environment variable.</p>
</li>
<li><p>In our example, we are focused on accessing the .env file and it has <code>Getenv()</code> a function that receives the values of environment variables named by <code>key</code></p>
</li>
</ul>
<hr />
<ul>
<li>Now let’s write <code>LoadEnv()</code> function</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> (...)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">LoadEnv</span><span class="hljs-params">()</span></span> {
    err := godotenv.Load(<span class="hljs-string">"../.env"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(<span class="hljs-string">"Error loading .env file"</span>)
    }
}
</code></pre>
<ul>
<li><p>We get <code>Load()</code> function inside <code>godotenv</code> package. <code>Load</code> will read the <code>.env</code> file and load them into ENV for this process. Notice that you pass the path of your .env file.</p>
</li>
<li><p>This function returns an error so we are collecting it inside <code>err</code> variable and then checking if the <code>err</code> has anything. If the <code>err</code> is not <code>nil</code> which means something went wrong. If so, we need to show the error message and exit the program. Because if the env file is not loaded then there is no point in starting the program.</p>
</li>
<li><p>Now to get a specific value from the env file we need to make one function that will get us the value of the asked key from the env file</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> config

<span class="hljs-keyword">import</span> (...)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">LoadEnv</span><span class="hljs-params">()</span></span> {
    ...
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetEnv</span><span class="hljs-params">(key, fallback <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
    <span class="hljs-keyword">if</span> value, ok := os.LookupEnv(key); ok {
        <span class="hljs-keyword">return</span> value
    }
    <span class="hljs-keyword">return</span> fallback
}
</code></pre>
<ul>
<li><p>We created the <code>GetEnv</code> function, which takes <code>key</code> and <code>fallback</code> strings as parameters and returns a string.</p>
</li>
<li><p>The <code>key</code> is the string for which we need the value in our code. For example, inside our <code>.env</code> file, we have different values. If we need only <code>DB_USER</code>, we pass this key to the function, and it returns the related value.</p>
</li>
<li><p>We also accept a fallback string, so if the requested value isn’t found, we use the default fallback value.</p>
</li>
<li><p>Here, we are using the <code>os</code> package, which includes the <code>LookupEnv</code> function. This function takes a <code>key</code> as an argument and returns two things: a <code>string</code> and a <code>bool</code>. If the value is found, <code>ok</code> will be true; otherwise, it will be false. By checking <code>ok</code>, we can determine if a value was returned and decide whether to return the fallback value.</p>
</li>
<li><p>Let’s check if it is working or not</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>

    <span class="hljs-string">"github.com/red-star25/crud-api/config"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    config.LoadEnv()
    fmt.Println(config.GetEnvValue(<span class="hljs-string">"DB_USER"</span>, <span class="hljs-string">"root"</span>))

       <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Setup database connection</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Setup router</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Run server</span>
}
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-go">root
</code></pre>
<ul>
<li>That’s awesome. Let’s now set out the Database Connection</li>
</ul>
<hr />
<h1 id="heading-setting-up-the-database-connection">Setting Up the Database Connection</h1>
<h2 id="heading-importing-packages">Importing Packages</h2>
<ul>
<li><p>As you know we are using MySQL for storing our application’s data. We need to first set up the connection and create an instance of the SQL DB.</p>
</li>
<li><p>Head over to <code>db.go</code> file and let’s first import all the required packages</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> database

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"database/sql"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"os"</span>

    _ <span class="hljs-string">"github.com/go-sql-driver/mysql"</span>
)
</code></pre>
<ul>
<li><p>We have seen the usage of <code>fmt</code>, <code>log</code> and <code>os</code>. Let’s see what are the remaining ones.</p>
</li>
<li><p><code>database/sql</code>: This is a built-in library for SQL database interactions.</p>
</li>
<li><p><code>_ "</code><a target="_blank" href="http://github.com/go-sql-driver/mysql"><code>github.com/go-sql-driver/mysql</code></a><code>"</code>: Imports the MySQL driver as a side effect to register it with <code>database/sql</code>. Here <code>_</code> (underscore) represent that this import is used as a side effect. Which means this package is not directly used.</p>
</li>
</ul>
<h2 id="heading-creating-database">Creating Database</h2>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> DB *sql.DB
</code></pre>
<ul>
<li><p>Here type DB is a pointer to <code>sql.DB</code> an object. We are making it globally accessible so that anyone can reuse it without creating it again and again on each query</p>
</li>
<li><p>You must be wondering Why it is a type of pointer.</p>
<ul>
<li><p>So, If <code>DB</code> were a simple variable (not a pointer), any changes made to it inside a function, wouldn't affect the global variable itself. Instead, Go would create a copy of the value, and the global <code>DB</code> would remain unchanged.</p>
</li>
<li><p>By using a pointer, it updates the global <code>DB</code> directly. This makes the database connection immediately available to all parts of the application.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-connect-function">Connect function</h2>
<ul>
<li>Now let’s create a function <code>Connect</code> that will be responsible for opening the database connection and making a connection.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Connect</span><span class="hljs-params">()</span></span> {
    dsn := fmt.Sprintf(<span class="hljs-string">"%s:%s@tcp(%s)/%s"</span>,
        config.GetEnvValue(<span class="hljs-string">"DB_USER"</span>, <span class="hljs-string">"root"</span>),
        config.GetEnvValue(<span class="hljs-string">"DB_PASSWORD"</span>, <span class="hljs-string">""</span>),
        config.GetEnvValue(<span class="hljs-string">"DB_HOST"</span>, <span class="hljs-string">"localhost"</span>),
        config.GetEnvValue(<span class="hljs-string">"DB_NAME"</span>, <span class="hljs-string">"crud_api"</span>),
    )
}
</code></pre>
<ul>
<li><p>Here we have created a variable <code>dsn</code>(Data Source Name) which is a type of string. So before we connect to MySQL we need to have a URL to which we want to connect.</p>
</li>
<li><p>So here we have used a formatted string from <code>fmt</code> package. Here function <code>Sprintf</code> returns a formatted string without printing it to the console. <code>%s</code> is a placeholder for <code>string</code> values here.</p>
</li>
<li><p>And we are getting all the values from our <code>.env</code> file using config’s <code>GetEnvValue</code> function.</p>
</li>
<li><p>Example <code>dsn</code></p>
</li>
</ul>
<pre><code class="lang-plaintext">username:password@tcp(localhost)/mydatabase
</code></pre>
<h2 id="heading-opening-connection">Opening Connection</h2>
<ul>
<li><p>Now that our data source URL is ready, we are ready to open our SQL connection.</p>
</li>
<li><p>To do that <code>mysql</code> provides <code>Open()</code> function which takes</p>
<ul>
<li><p><code>driverName</code> (which is nothing but a database name, ex: MySQL, MongoDB, Postgres, etc). You can provide any driver here and open the connection and</p>
</li>
<li><p><code>dataSourceName</code> is a URL of the database that we just created above.</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> err error
DB, err = sql.Open(<span class="hljs-string">"mysql"</span>, dsn)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    log.Fatalf(<span class="hljs-string">"Error connecting to database: %v"</span>, err)
}
</code></pre>
<ul>
<li><p>This function returns two things: <code>db</code> object and <code>err</code>.</p>
</li>
<li><p>So what we are doing here is, we are assigning the returned SQL db object to our globally defined <strong>DB</strong>.</p>
</li>
<li><p>And then we check if there is any error occurred or not.</p>
</li>
</ul>
<blockquote>
<p>You will see this type of error handling thoughtout any Go project. This is a convention in Go. It might seems little overdoing but it is a good practice that we are handling error just after calling function.</p>
<p>Also note that there is no <code>try</code> <code>catch</code> or <code>finally</code> keywords in Go. You can read why they are using this type of error handling in this article : <a target="_blank" href="https://go.dev/doc/faq#exceptions">https://go.dev/doc/faq#exceptions</a></p>
</blockquote>
<h2 id="heading-verifying-the-db-connection">Verifying the DB Connection</h2>
<ul>
<li>To verify whether the connection is successful or not we have <code>Ping</code> function that verifies if the database connection is still alive, and it also establishes the connection if necessary.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> err := DB.Ping(); err != <span class="hljs-literal">nil</span> {
    log.Fatalf(<span class="hljs-string">"Error verifying database connection: %v"</span>, err)
}
</code></pre>
<ul>
<li>That’s pretty much it. We can log the message after this that the Database is connected successfully.</li>
</ul>
<h2 id="heading-final-dbgo-code">Final <code>db.go</code> code</h2>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> database

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"database/sql"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>

    _ <span class="hljs-string">"github.com/go-sql-driver/mysql"</span>
    <span class="hljs-string">"github.com/red-star25/crud-api/config"</span>
)

<span class="hljs-keyword">var</span> DB *sql.DB

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Connect</span><span class="hljs-params">()</span></span> {
    dsn := fmt.Sprintf(<span class="hljs-string">"%s:%s@tcp(%s)/%s"</span>,
        config.GetEnvValue(<span class="hljs-string">"DB_USER"</span>, <span class="hljs-string">"root"</span>),
        config.GetEnvValue(<span class="hljs-string">"DB_PASSWORD"</span>, <span class="hljs-string">""</span>),
        config.GetEnvValue(<span class="hljs-string">"DB_HOST"</span>, <span class="hljs-string">"localhost"</span>),
        config.GetEnvValue(<span class="hljs-string">"DB_NAME"</span>, <span class="hljs-string">"crud_api"</span>),
    )

    <span class="hljs-keyword">var</span> err error
    DB, err = sql.Open(<span class="hljs-string">"mysql"</span>, dsn)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatalf(<span class="hljs-string">"Error connecting to database: %v"</span>, err)
    }

    <span class="hljs-keyword">if</span> err := DB.Ping(); err != <span class="hljs-literal">nil</span> {
        log.Fatalf(<span class="hljs-string">"Error verifying database connection: %v"</span>, err)
    }

    log.Println(<span class="hljs-string">"Database connected successfully!"</span>)

}
</code></pre>
<ul>
<li>And now call this <code>Connect</code> function inside <code>main.go</code></li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"github.com/red-star25/crud-api/config"</span>
    <span class="hljs-string">"github.com/red-star25/crud-api/database"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    config.LoadEnv()

    database.Connect()

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Setup router</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Run server</span>

}
</code></pre>
<ul>
<li><p>If everything goes right then you will see this message after you run the program.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736390331806/d9bc489e-a75f-4469-952b-122406a2af13.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Make sure you have MySQL up and running on your computer.</p>
</blockquote>
</li>
</ul>
<hr />
<h1 id="heading-creating-book-model">Creating <code>Book</code> model</h1>
<ul>
<li>We are creating CRUD API for managing Books. So in order to view data in a structured manner with all the required fields we need to create a Book model using <code>struct</code></li>
</ul>
<blockquote>
<p>In Go, the term <strong>"model"</strong> refers to a structured representation of data used within an application, typically to map data between a program and an external data source, such as a database or an API. Models are often implemented as <code>structs</code> in Go, which are a way to define and organize related data fields.</p>
</blockquote>
<ul>
<li>Let’s create our Book model</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// internal/books/model.go</span>
<span class="hljs-keyword">package</span> books

<span class="hljs-keyword">type</span> Book <span class="hljs-keyword">struct</span> {
    ID     <span class="hljs-keyword">int</span>
    Title  <span class="hljs-keyword">string</span>
    Author <span class="hljs-keyword">string</span>
    Year   <span class="hljs-keyword">int</span>
}
</code></pre>
<ul>
<li><p>Here we have four fields inside our Book struct. <code>ID</code>, <code>Title</code>, <code>Author</code>, <code>Year</code>.</p>
</li>
<li><p>That’s easy, right? Yes. But there is one more thing which we need to do. So as we know that when we deal with APIs, we use JSON to serialize and deserialize the data that we are getting from the user and data we are sending to the user.</p>
</li>
<li><p>And generally, they are represented in lowercase like <code>id</code>, <code>name</code>, <code>author</code>, <code>year</code> like that. But if you see our Book struct we have the first letter capital for each field. And that is intentional. Because we need those struct’s fields outside to use. And to make it globally accessible we capitalize the first letter of any variable.</p>
</li>
<li><p>So to resolve this issue, we use what we call in go “ <strong>struct tags “</strong>. In other programming languages, we refer to this as “ <strong>annotations</strong> “.</p>
</li>
<li><p>This helps us convert these struct fields to proper naming conventions. Let’s see how we do that</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> books

<span class="hljs-keyword">type</span> Book <span class="hljs-keyword">struct</span> {
    ID     <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"id"`</span>
    Title  <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"title"`</span>
    Author <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"author"`</span>
    Year   <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"year"`</span>
}
</code></pre>
<ul>
<li>So what we do is after giving the type of the struct field we use backticks ` `. And in there we write json: and then whatever name we want.</li>
</ul>
<hr />
<h1 id="heading-implement-database-queries-crud">Implement Database Queries (CRUD)</h1>
<ul>
<li><p>Now that our database is up and running let’s write database queries for <strong>C</strong>reate, <strong>R</strong>ead, <strong>U</strong>pdate, and <strong>D</strong>elete.</p>
</li>
<li><p>First of all, let’s import two required packages</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> books

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crud-api/internal/database"</span>
    <span class="hljs-string">"errors"</span>
)
</code></pre>
<ul>
<li><p>We are importing a database for accessing the <strong>DB</strong> object. Using this we can perform all the queries.</p>
</li>
<li><p>And <code>errors</code> we use for handling errors.</p>
</li>
</ul>
<h2 id="heading-the-getallbooks-function">The <code>GetAllBooks</code> Function</h2>
<ul>
<li>Firstly we are creating a function to get all the books from the database</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetAllBooks</span><span class="hljs-params">()</span> <span class="hljs-params">([]Book, error)</span></span> {
    rows, err := database.DB.Query(<span class="hljs-string">"SELECT * FROM books"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, err
    }
    <span class="hljs-keyword">defer</span> rows.Close()

    ...
}
</code></pre>
<ul>
<li><p>Here we created a function called <code>GetAllBooks</code> which is responsible for getting all the books from the database.</p>
</li>
<li><p>It returns two values:</p>
<ul>
<li><p><strong>[ ]Book:</strong> A slice of struct Book.</p>
</li>
<li><p><strong>error:</strong> Go’s error object.</p>
</li>
</ul>
</li>
<li><p>Inside the function body, we are making a query to the SQL database using the DB variable’s <code>Query</code> function. It takes a string where we write a raw SQL query.</p>
</li>
<li><p>In this function, we need all the books with data. And to do that we wrote this query <strong>“SELECT * FROM books“.</strong> Which will get all the books from the database.</p>
</li>
<li><p>And then we checked if it threw any errors</p>
</li>
<li><p>After that, we defer call the rows.Close() to close it once this function is finished.</p>
</li>
</ul>
<hr />
<ul>
<li><p>This <code>rows</code> object allows us to iterate over the results we get from the Query. And to iterate over the results we have <code>rows.Next()</code> function which goes over all the results.</p>
</li>
<li><p>We can take advantage of this function and create a for loop inside which we can fill all the data inside a slice of the book</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetAllBooks</span><span class="hljs-params">()</span> <span class="hljs-params">([]Book, error)</span></span> {    
    ...
    <span class="hljs-keyword">var</span> books []Book
    <span class="hljs-keyword">for</span> rows.Next() {
        <span class="hljs-keyword">var</span> book Book
        <span class="hljs-keyword">if</span> err := rows.Scan(&amp;book.ID, &amp;book.Title, &amp;book.Author, &amp;book.Year); err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, err
        }
        books = <span class="hljs-built_in">append</span>(books, book)
    }
    <span class="hljs-keyword">return</span> books, <span class="hljs-literal">nil</span>
}
</code></pre>
<ul>
<li><p>Here we have created a temporary slice of the book variable. In this, we will fill in all the data.</p>
</li>
<li><p>Then we looped through <code>rows.Next()</code> which will go over all the rows and inside the for the body we are getting all mapping the data in a row to the Book struct using <code>rows.Scan</code></p>
</li>
<li><p>And after that, we are appending that book to the <code>books</code> slice</p>
</li>
<li><p>And once every row is scanned we return it from the function.</p>
</li>
</ul>
<blockquote>
<p>NOTE: Make sure you have the book table in MySQL database: If you don’t have one then create it and then run the project, otherwise it will throw an error</p>
<p>You can run this query inside your MySQL Workbench</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> books (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INT</span> AUTO_INCREMENT PRIMARY <span class="hljs-keyword">KEY</span>,
    title <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    author <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    <span class="hljs-keyword">year</span> <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);
</code></pre>
</blockquote>
<ul>
<li>Let’s test <code>GetAllBooks</code>.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// main.go</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    config.LoadEnv()

    database.Connect()

    data, err := books.GetAllBooks()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    fmt.Println(<span class="hljs-string">"Books:"</span>,data)
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Setup router</span>

    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Run server</span>

}
</code></pre>
<p><strong>Output:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736402535605/d8d513dd-ea92-4969-b88d-14a69dd7b53a.png" alt class="image--center mx-auto" /></p>
<ul>
<li>It ran!!!!</li>
</ul>
<p><img src="https://media.tenor.com/jfufeww3U04AAAAM/jeff-blim-starkid.gif" alt="a man in a suit and black turtleneck is giving a yes sign" class="image--center mx-auto" /></p>
<hr />
<ul>
<li><p>This is great! Now let’s create a Handler function for this function. Because we need to send this data to the user too, right? Till now we just got the data from the database.</p>
</li>
<li><p>To do that head over to <code>handler.go</code> file</p>
</li>
</ul>
<hr />
<h1 id="heading-setting-up-http-handlers">Setting up HTTP Handlers</h1>
<ul>
<li>Let’s first import the required packages</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// handler.go</span>

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"net/http"</span>
)
</code></pre>
<ul>
<li><p>Here <code>encoding/json</code> is used. This is used for converting JSON data into Go structures and Go data structures into JSON.</p>
</li>
<li><p><code>net/http</code> is used for handling HTTP requests.</p>
</li>
<li><p>I’ll first show all the code to you and then we will understand what it does</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> books

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"net/http"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetAllBooksHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    books, err := GetAllBooks()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        http.Error(w, <span class="hljs-string">"Failed to fetch books"</span>, http.StatusInternalServerError)
        <span class="hljs-keyword">return</span>
    }

    w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
    json.NewEncoder(w).Encode(books)
}
</code></pre>
<ul>
<li><p><code>func GetAllBooksHandler(w http.ResponseWriter, r *http.Request) {</code></p>
<ul>
<li><p>Here we have two parameters:</p>
<ul>
<li><p><code>w http.ResponseWriter</code>: This is used for sending data back to the client.</p>
</li>
<li><p><code>r *http.Request</code>: This is used for getting data from the client.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="heading-fetching-the-books">Fetching the Books</h2>
<ul>
<li><p><code>books, err := GetAllBooks()</code></p>
<ul>
<li>Here, the function <code>GetAllBooks</code> is called to retrieve a list of books. As we saw, that function will get the data from the database and return all the books with an err object.</li>
</ul>
</li>
</ul>
<h2 id="heading-error-handling">Error Handling</h2>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    http.Error(w, <span class="hljs-string">"Failed to fetch books"</span>, http.StatusInternalServerError)
    <span class="hljs-keyword">return</span>
}
</code></pre>
<ul>
<li><p>If that function returns any error, we check it inside this if block and send back the HTTP error of <code>InternalServerError</code>.</p>
</li>
<li><p>And then exiting the function with <code>return</code></p>
</li>
<li><p>Here, The <code>http.Error</code> function simplifies sending error responses. This has all the different types of errors you can throw according to your functionalities.</p>
</li>
</ul>
<h2 id="heading-setting-the-response-header">Setting the Response Header</h2>
<pre><code class="lang-go">w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
</code></pre>
<ul>
<li>This line sets the <code>Content-Type</code> header of the response to <code>application/json</code>. It informs the client that the response body contains JSON data.</li>
</ul>
<h2 id="heading-encoding-and-sending-the-response">Encoding and Sending the Response</h2>
<pre><code class="lang-go">json.NewEncoder(w).Encode(books)
</code></pre>
<ul>
<li><p>Now we need to encode the slice of a book in JSON format for the client. To do data we use json Encoder method.</p>
</li>
<li><p>This sent the data as the HTTP response. And it ensures compatibility with clients expecting data in JSON format.</p>
</li>
</ul>
<hr />
<h1 id="heading-configuring-routes">Configuring Routes</h1>
<ul>
<li><p>Now, how these handlers are going to trigger? Of course when the user hits a certain URL, or to be specific an Endpoint from their end.</p>
</li>
<li><p>And so we want to return data for that particular endpoint/route right? For that, we need to create a route called <code>/book</code>.</p>
</li>
<li><p>And to create routes we are using the <strong>Chi package</strong>.</p>
</li>
<li><p>Go to <code>routes.go</code> and paste the below code</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> routes

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crud-api/internal/books"</span>

    <span class="hljs-string">"github.com/go-chi/chi/v5"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">SetupRouter</span><span class="hljs-params">()</span> *<span class="hljs-title">chi</span>.<span class="hljs-title">Mux</span></span> {
    r := chi.NewRouter()

    r.Get(<span class="hljs-string">"/books"</span>, books.GetAllBooksHandler)

    <span class="hljs-keyword">return</span> r
}
</code></pre>
<ul>
<li><p>Here the SetupRouter function will configure all the routes.</p>
</li>
<li><p>First, we need to create an instance of chi router. This router will handle the incoming HTTP requests and route them to the appropriate handlers.</p>
</li>
<li><p><code>r := chi.NewRouter()</code> - This line does that</p>
</li>
<li><p>And now using this variable <code>r</code> we can create a map of the routes to the handlers.</p>
</li>
</ul>
<pre><code class="lang-go">r.Get(<span class="hljs-string">"/books"</span>, books.GetAllBooksHandler)
</code></pre>
<ul>
<li><p>For different HTTP request, we have different HTTP Methods in <code>r</code>. POST, UPDATE, DELETE,etc</p>
</li>
<li><p>Here we need GET as we are getting the data from the database. Inside <code>r.Get()</code>, first, we need to give the route as <code>/books</code>. This means once this endpoint is hit by the client, the handler defined in the second parameter will be triggered.</p>
</li>
<li><p>And at the end, we are returning the pointer to the chi.Mux because we need it for the server in the <code>main.go</code>. You will see why below.</p>
</li>
</ul>
<hr />
<h1 id="heading-finalizing-the-maingo-file">Finalizing the <code>main.go</code> file</h1>
<ul>
<li>Now that we have everything set up we can start the server and listen to the endpoints.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>

    <span class="hljs-string">"github.com/red-star25/crud-api/config"</span>
    <span class="hljs-string">"github.com/red-star25/crud-api/database"</span>
    <span class="hljs-string">"github.com/red-star25/crud-api/internal/routes"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    config.LoadEnv()
    database.Connect()

    router := routes.SetupRouter()
    port := config.GetEnvValue(<span class="hljs-string">"PORT"</span>, <span class="hljs-string">"8080"</span>)
    log.Printf(<span class="hljs-string">"Server running on port %s"</span>, port)
    log.Fatal(http.ListenAndServe(<span class="hljs-string">":"</span>+port, router))
}
</code></pre>
<ul>
<li><p>Inside the main function, we are loading the environment variables.</p>
</li>
<li><p>Then we connect to the database.</p>
</li>
<li><p>And then we call SetupRouter to configure all the routes.</p>
</li>
<li><p>To run the server we have <code>ListenAndServe</code> function inside <code>http</code> package. Inside we have to first pass the address and then the router that we set up. And we also have to check for any errors. So we are wrapping this function inside <code>log.Fatal</code></p>
</li>
</ul>
<hr />
<h1 id="heading-running-the-server">Running The Server</h1>
<ul>
<li><p>Now let’s cross our fingers and check if everything is working. To check the functionality of our program. We are using the Postman application.</p>
</li>
<li><p>So open it up and run it</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736405665069/0aeaacae-70a0-400d-abec-0600f04fdd56.png" alt class="image--center mx-auto" /></p>
<p><img src="https://media1.tenor.com/m/J8GV21cQO3QAAAAd/bb-baby.gif" alt="a baby is sitting in a crowd with a woman holding him and screaming yes ." class="image--center mx-auto" /></p>
<ul>
<li>You will see an empty slice because we have not added any data yet. We will be implementing other HTTP methods in the next article.</li>
</ul>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li><p>If you came this far to the end of this article, then congratulations for making it.</p>
</li>
<li><p>In the next article, we will be implementing the remaining CRUD operations which are Update, Delete, and Create. It will be fun because now we have the base setup for us, so now we just need to work on the functionalities.</p>
</li>
<li><p>Hope you learned something from this article. There are lots of blogs coming in the future with more amazing topics and projects and I am so excited to write about all of it.</p>
</li>
<li><p>See you in the next blog, until then….</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm&amp;auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a>, <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a>, and <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Zero to Go Hero: Learn Go Programming with Me - Part 3]]></title><description><![CDATA[Introduction

Welcome to Part 3 of the Learning Go with Me series. I hope you like it so far and learned from it. Because that’s the most important thing. If you have any doubts or comments please feel free to comment it. I will try to help you out.
...]]></description><link>https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-3</link><guid isPermaLink="true">https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-3</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Developer]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[learning]]></category><category><![CDATA[development]]></category><category><![CDATA[backend]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Thu, 09 Jan 2025 21:16:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736195375027/69c04f72-f889-4f38-b4e4-6ffce98a879c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Welcome to Part 3 of the Learning Go with Me series. I hope you like it so far and learned from it. Because that’s the most important thing. If you have any doubts or comments please feel free to comment it. I will try to help you out.</p>
</li>
<li><p>In the last article, we learned lots of fundamental concepts of Go. And in this blog, I decided to just focus on the Pointers.</p>
</li>
<li><p>Let’s start without further ado</p>
</li>
</ul>
<hr />
<h1 id="heading-what-is-a-pointer">What is a Pointer?</h1>
<ul>
<li><p>A pointer is nothing but a variable that stores the “<strong>memory address”</strong> of another variable. What does that mean?</p>
</li>
<li><p>So instead of holding a direct value which we typically do like <code>age := 24</code>, the pointer holds the address of where that value is stored in memory.</p>
</li>
<li><p>You can think of pointers as post office boxes.</p>
</li>
</ul>
<p><img src="https://t4.ftcdn.net/jpg/01/78/09/19/240_F_178091901_TN6QoOQnM7HJ1iMAkyS7effr1zoaJK5c.jpg" alt="Mail boxes filled of leaflets and letters. Shallow DOF,Mailboxes and Lock in Rows at Entrance." class="image--center mx-auto" /></p>
<ul>
<li>Each box points to a certain address/ house number. Similarly, if you have defined a variable like this:</li>
</ul>
<pre><code class="lang-go">num := <span class="hljs-number">42</span>
</code></pre>
<ul>
<li>Then you can point to this variable using another variable with a pointer</li>
</ul>
<pre><code class="lang-go">ptr := &amp;num
</code></pre>
<ul>
<li>You need to first understand what ‘ <strong>* ‘ and ‘ &amp; ’</strong> lexical elements mean.</li>
</ul>
<ol>
<li><p><strong>Address Operator (&amp;):</strong></p>
<ul>
<li>The &amp; operator is used to get the memory address of a variable. If <code>x</code> is an integer variable then <code>&amp;x</code> will give you pointers to <code>x</code> that is, a memory address where the integer <code>x</code> is stored.</li>
</ul>
</li>
<li><p><strong>Dereferencing Operator ( * ):</strong></p>
<ul>
<li>The * operator is used to get the value stored at a memory address. If <code>p</code> is a pointer to an integer, then <code>*p</code> will give you the integer that <code>p</code> points to.</li>
</ul>
</li>
</ol>
<p><strong>Example:</strong></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>{
    num := <span class="hljs-number">42</span>
    ptr:= &amp;num

    fmt.Println(ptr) <span class="hljs-comment">// 0xc000104040 - Address where num is stored</span>
    fmt.Println(*ptr) <span class="hljs-comment">// 43 - Value at which ptr is pointing</span>
}
</code></pre>
<ul>
<li>In this example, <code>ptr</code> is a pointer to <code>num</code>. You can get the value of <code>num</code> by dereferencing <code>ptr</code> with <code>*ptr</code>.</li>
</ul>
<hr />
<h1 id="heading-passing-pointer-to-functions">Passing Pointer to Functions</h1>
<ul>
<li><p>Pointers also come into play when you're dealing with functions.</p>
</li>
<li><p>If you pass a variable to a function in Go, the function gets a copy of the variable. <strong>Everything in go is a pass-by value</strong>, if the function changes the variable, it won't affect the original. But if you pass a pointer to a variable, the function can dereference the pointer to change the original variable.</p>
</li>
<li><p>Let’s take an example</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// Without Pointer - Pass by Value</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">valueSemantic</span><span class="hljs-params">(num <span class="hljs-keyword">int</span>)</span></span>{
    num = <span class="hljs-number">43</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>{
    num := <span class="hljs-number">42</span>

    fmt.Println(<span class="hljs-string">"Before: "</span>, num) <span class="hljs-comment">// 42</span>

    valueSemantic(num)

    fmt.Println(<span class="hljs-string">"After: "</span>, num) <span class="hljs-comment">// 42</span>
}
</code></pre>
<ul>
<li>This is because a copy of num is getting passed to the function <code>valueSemantic</code> and not the actual value. To update the value that we are passing from other functions we have to use a pointer.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// With pointer - Pass by Value</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">valueSemantic</span><span class="hljs-params">(num *<span class="hljs-keyword">int</span>)</span></span>{
    *num = <span class="hljs-number">43</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>{
    num := <span class="hljs-number">42</span>

    fmt.Println(<span class="hljs-string">"Before: "</span>, num) <span class="hljs-comment">// 42</span>

    valueSemantic(&amp;num)

    fmt.Println(<span class="hljs-string">"After: "</span>, num) <span class="hljs-comment">// 43</span>
}
</code></pre>
<ul>
<li><p>As you can see now it got changed. Why?</p>
</li>
<li><p>Because now we are not passing just the copy of the <code>num</code> but we are passing it an address where <code>num</code> is stored.</p>
</li>
<li><p>And in the function parameter now that we are passing an address to it we need to accept that address using a pointer. Because remember? The pointer points to another variable’s address.</p>
</li>
<li><p>Inside the function, we can’t just do this and change the variable:</p>
</li>
</ul>
<pre><code class="lang-go">num = <span class="hljs-number">43</span>
</code></pre>
<ul>
<li>Because <code>num</code> is a pointer. So first we need to get the value of that pointer by dereferencing it like this <code>*num</code> and then assign a new value to it.</li>
</ul>
<pre><code class="lang-go">*num = <span class="hljs-number">43</span>
</code></pre>
<hr />
<h1 id="heading-pointers-with-structs">Pointers with Structs</h1>
<ul>
<li><p>Lastly, pointers are crucial when dealing with structs in Go. Since Go doesn’t have classes</p>
<p>  and objects, you can use structs to create complex types, and you can use pointers to structs to modify these structs or to avoid copying the structs around.</p>
</li>
<li><p>Let’s take an example:</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    name <span class="hljs-keyword">string</span>
    age  <span class="hljs-keyword">int</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateName</span><span class="hljs-params">(p *Person, newName <span class="hljs-keyword">string</span>)</span></span> {
    p.name = newName <span class="hljs-comment">// Modify the struct via pointer</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    p := Person{name: <span class="hljs-string">"Alice"</span>, age: <span class="hljs-number">30</span>}

    fmt.Println(<span class="hljs-string">"Before:"</span>, p.name) <span class="hljs-comment">// Prints: Alice</span>
    updateName(&amp;p, <span class="hljs-string">"Bob"</span>)
    fmt.Println(<span class="hljs-string">"After:"</span>, p.name) <span class="hljs-comment">// Prints: Bob</span>
}
</code></pre>
<ul>
<li><p>We aren’t doing anything new in this. We created a struct of type Person. It has <code>name</code> and <code>age</code> fields.</p>
</li>
<li><p>And inside <code>main</code> function we are passing the address of this person <code>p</code> in <code>updateName</code> function.</p>
</li>
<li><p><code>updateName</code> takes two parameters. Pointer to a struct person and new name.</p>
</li>
<li><p>But inside the function, you see we didn’t use <code>*</code> to deference it. Why?</p>
</li>
<li><p>This is because Go is automatically dereferencing that struct for us. So when you have a pointer to a struct in Go, the language provides a convenience called <strong>automatic dereferencing</strong> for accessing fields or calling methods. You don't need to explicitly dereference the pointer using <code>*</code> before accessing fields or methods.</p>
</li>
</ul>
<blockquote>
<p><strong>For Primitive Types (e.g., int, float, etc.):</strong> You must use <code>*</code> to dereference the pointer and access the value.</p>
<p><strong>For Structs:</strong> Go <strong>automatically dereferences pointers to structs</strong> when you access their fields or call methods.</p>
</blockquote>
<hr />
<ul>
<li>In my previous blog, I forgot two concepts to discuss which are <code>defer</code> and <code>switch case</code> statements. Let’s understand them one by one</li>
</ul>
<hr />
<h1 id="heading-defer">defer</h1>
<ul>
<li><p>In Go, the <code>defer</code> the keyword is used to ensure that a function call is executed later in a program’s execution, usually for the purposes of cleanup.</p>
</li>
<li><p><code>defer</code> is often used where <code>ensure</code> and <code>finally</code> would be used in other languages.</p>
</li>
<li><p>When a function call is deferred, it's placed onto a stack. The function calls on the stack are executed when the surrounding function returns, not when the <code>defer</code> the statement is called.</p>
</li>
<li><p>They're executed in Last In, First Out (LIFO) order, so if you have multiple <code>defer</code> statements, the most recently deferred function will be the first one to execute when the function returns.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"Start"</span>)

    <span class="hljs-keyword">defer</span> fmt.Println(<span class="hljs-string">"This will print last"</span>)

    fmt.Println(<span class="hljs-string">"End"</span>)
}
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-go">Start
End
This will <span class="hljs-built_in">print</span> last
</code></pre>
<h2 id="heading-multiple-defer-statements">Multiple <code>defer</code> Statements</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">defer</span> fmt.Println(<span class="hljs-string">"First"</span>)
    <span class="hljs-keyword">defer</span> fmt.Println(<span class="hljs-string">"Second"</span>)
    <span class="hljs-keyword">defer</span> fmt.Println(<span class="hljs-string">"Third"</span>)
}
</code></pre>
<p><strong>Output</strong></p>
<pre><code class="lang-go">Third
Second
First

<span class="hljs-comment">// LIFO order as explained above</span>
</code></pre>
<h2 id="heading-real-world-example-closing-a-file">Real-World Example: Closing a File</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    file, err := os.Open(<span class="hljs-string">"example.txt"</span>) <span class="hljs-comment">// Opening a file</span>
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Println(<span class="hljs-string">"Error opening file:"</span>, err)
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">defer</span> file.Close() <span class="hljs-comment">// Ensure the file is closed before exiting the function</span>

    <span class="hljs-comment">// Perform file operations here...</span>
    fmt.Println(<span class="hljs-string">"File opened successfully"</span>)
}
</code></pre>
<ul>
<li><p>In real-world programming, we have many things open. We need to make sure we close those types of functions because otherwise, it will create memory leakage. Although Go has a Garbage collector that will dump those things down if not used, but it’s always a good practice to close the instance of it once the work is done.</p>
</li>
<li><p>And that’s where <code>defer</code> can be used. We use defer right after we perform operations like opening a file to make sure we don’t forget.</p>
</li>
</ul>
<hr />
<h1 id="heading-switch">Switch</h1>
<ul>
<li><code>switch</code> in Go is a powerful way to control the flow of execution by matching a value against multiple cases. It is simpler and cleaner than writing multiple <code>if-else</code> conditions.</li>
</ul>
<h2 id="heading-how-switch-works">How <code>switch</code> works</h2>
<ul>
<li><p><code>switch</code> evaluates a value and executes the first matching <code>case</code>.</p>
</li>
<li><p>If no <code>case</code> matches, the <code>default</code> block if executed.</p>
</li>
</ul>
<h2 id="heading-example">Example</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    day := <span class="hljs-string">"Monday"</span>

    <span class="hljs-keyword">switch</span> day {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"Monday"</span>:
        fmt.Println(<span class="hljs-string">"Start of the workweek!"</span>)
    <span class="hljs-keyword">case</span> <span class="hljs-string">"Friday"</span>:
        fmt.Println(<span class="hljs-string">"Almost the weekend!"</span>)
    <span class="hljs-keyword">default</span>:
        fmt.Println(<span class="hljs-string">"Just another day."</span>)
    }
}
</code></pre>
<ul>
<li><p>In the above example, the <code>switch</code> matches <code>day</code> to <code>Monday</code> and executes the corresponding block</p>
</li>
<li><p>In Go we can use Switch without an Expression. So If we omit the expression, Go evaluates the first <code>case</code> that is <code>true</code></p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    x := <span class="hljs-number">15</span>

    <span class="hljs-keyword">switch</span> {
    <span class="hljs-keyword">case</span> x &lt; <span class="hljs-number">10</span>:
        fmt.Println(<span class="hljs-string">"Less than 10"</span>)
    <span class="hljs-keyword">case</span> x &lt; <span class="hljs-number">20</span>:
        fmt.Println(<span class="hljs-string">"Between 10 and 20"</span>) <span class="hljs-comment">// Prints this</span>
    <span class="hljs-keyword">default</span>:
        fmt.Println(<span class="hljs-string">"20 or more"</span>)
    }
}
</code></pre>
<h2 id="heading-fallthrough-in-switch">Fallthrough in <code>switch</code></h2>
<ul>
<li>The <code>fallthrough</code> keyword forces the execution of the next case, even if the condition is not <code>true</code></li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    num := <span class="hljs-number">2</span>

    <span class="hljs-keyword">switch</span> num {
    <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
        fmt.Println(<span class="hljs-string">"One"</span>)
    <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
        fmt.Println(<span class="hljs-string">"Two"</span>)
        <span class="hljs-keyword">fallthrough</span>
    <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:
        fmt.Println(<span class="hljs-string">"Three"</span>)
    <span class="hljs-keyword">default</span>:
        fmt.Println(<span class="hljs-string">"Other"</span>)
    }
}

<span class="hljs-comment">/* 
Output: 
Two 
Three
*/</span>
</code></pre>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li><p>In this article, we explored some of the fundamental concepts of Go, including pointers, defer statements, and switch statements.</p>
</li>
<li><p>We learned that pointers store the memory address of variables, enabling functions to modify original data without creating copies.</p>
</li>
<li><p>The <code>defer</code> statement schedules function calls to execute after the surrounding function completes.</p>
</li>
<li><p>The <code>switch</code> statement offers a good control flow based on variable values.</p>
</li>
<li><p>I think this is pretty much it for you to know to get started. So from the next article, we will start building out Book CRUD API. There are still a few things remaining to explain and I will be explaining on the go as it will make much more sense when we are building something.</p>
</li>
<li><p>I hope you have learned something from this article. If you have any feedback or queries, feel free to ask them in the comments. I’ll be happy to answer all your questions</p>
</li>
<li><p>See you in the next article, until then….</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong>, <strong>Linke</strong></a><a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>dIn</strong>, and <strong>Gi</strong></a><a target="_blank" href="https://github.com/red-star25"><strong>thub</strong>.</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Zero to Go Hero: Learn Go Programming with Me - Part 2]]></title><description><![CDATA[Introduction

Hey there! Welcome to Part 2 of the series of Learning Go with me. In Part 1 we set the stage by introducing the project, defining its goals, and setting up the basic folder structure for our Go project.

Now it’s time to dive deeper in...]]></description><link>https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-2</link><guid isPermaLink="true">https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-2</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Developer]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[development]]></category><category><![CDATA[learning]]></category><category><![CDATA[backend]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Wed, 08 Jan 2025 21:18:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736111954991/510adc38-ef21-493e-aa2f-062b4d2fde96.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Hey there! Welcome to Part 2 of the series of Learning Go with me. In Part 1 we set the stage by introducing the project, defining its goals, and setting up the basic folder structure for our Go project.</p>
</li>
<li><p>Now it’s time to dive deeper into some fundamental concepts of Go programming.</p>
</li>
<li><p>In this part, we’ll cover core topics like how Go organizes code using <strong>packages</strong> and <strong>imports,</strong> how <strong>exported names work,</strong> and explore <strong>basic Go constructs</strong> such as types, variables, constants, functions, slices, maps, loops, and conditionals. Then we’ll also understand how <strong>structs</strong> and <strong>pointers</strong> work.</p>
</li>
<li><p>I will try my best to explain each concept in a beginner-friendly way and in a way that I understand because I am also learning with you. I will try to incorporate these concepts in a way that after understanding it we can directly apply it to our CRUD API project.</p>
</li>
<li><p>By the end of this section, you’ll have a strong grasp of these concepts and be ready to use them to bring our API to life.</p>
</li>
<li><p>Let’s jump right in it without wasting any more time</p>
</li>
</ul>
<hr />
<h1 id="heading-packages">Packages</h1>
<h2 id="heading-what-is-a-package-in-go">What is a Package in Go?</h2>
<ul>
<li><p>In Go, packages are a way to organize and reuse code. What does that mean?</p>
</li>
<li><p>Think of a Package like a Folder on your computer. Inside that folder, you have related files. Similarly in Go, the files inside a package folder work together to provide some functionality</p>
</li>
<li><p>For example:</p>
<ul>
<li>If you are familiar with <code>math</code> package in any other language then you must know that it contains tons of mathematical operations. So all these operations are inside this math package</li>
</ul>
</li>
<li><p>And when you want these functions which are defined somewhere else inside your program, you use <strong>“import“.</strong></p>
</li>
</ul>
<h2 id="heading-types-of-packages">Types of Packages</h2>
<ol>
<li><p><strong>Standard Library Packages:</strong></p>
<ul>
<li>These are built-in packages in Go. Packages like <code>math</code> for mathematical operations, <code>net/http</code> for handling HTTP requests, <code>encoding/json</code> for working with JSON, etc.</li>
</ul>
</li>
<li><p><strong>Third-Party Packages:</strong></p>
<ul>
<li>These are the additional packages that are created by people in the Go community. If you remember, in Part 1 we installed a few dependencies using <code>go get</code> the command. Those belong to this type.</li>
</ul>
</li>
<li><p><strong>Custom Packages:</strong></p>
<ul>
<li>You can create your own packages too which you can use to organize code. We will see this in action soon.</li>
</ul>
</li>
</ol>
<h2 id="heading-how-packages-work">How Packages Work?</h2>
<ul>
<li><strong>In Go, every program belongs to a package.</strong> The <code>main</code> package is special because it’s where the program starts running. When we define the main package inside a file, Go will know from where it should start the program.</li>
</ul>
<h2 id="heading-using-packages-in-our-project">Using Packages in Our Project</h2>
<ul>
<li>In Part 1 we created different folders and files. If you have noticed, every folder and files are in <strong>red</strong> color which shows that something is wrong. This is because we need to tell which file belongs to which package. Let’s resolve this.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736114848714/e4de1df9-f335-49c4-b211-4b100b3474ee.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Go to each file and write the folder name as a package it belongs to.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// cmd/main.go</span>
<span class="hljs-keyword">package</span> main

<span class="hljs-comment">// config/config.go</span>
<span class="hljs-keyword">package</span> config

<span class="hljs-comment">// databse/db.go</span>
<span class="hljs-keyword">package</span> database

<span class="hljs-comment">// internal/books/handler.go, model.go and service.go</span>
<span class="hljs-keyword">package</span> books

<span class="hljs-comment">// routes/routes.go</span>
<span class="hljs-keyword">package</span> routes

<span class="hljs-comment">//pkg/logger</span>
<span class="hljs-keyword">package</span> logger
</code></pre>
<ul>
<li>All the errors should be gone after giving the package name inside every file.</li>
</ul>
<hr />
<h2 id="heading-imports">Imports</h2>
<ul>
<li>To use any package inside a Go project, we need to import it using <code>import</code> a keyword.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>
</code></pre>
<ul>
<li>If you have multiple packages then list them in parentheses</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>    <span class="hljs-comment">// for printing.</span>
    <span class="hljs-string">"net/http"</span>    <span class="hljs-comment">// to handle HTTP requests and responses.    </span>
    <span class="hljs-string">"encoding/json"</span>    <span class="hljs-comment">// to parse and generate JSON data</span>
)
</code></pre>
<hr />
<h1 id="heading-exported-names">Exported Names</h1>
<h2 id="heading-what-are-exported-names">What Are Exported Names?</h2>
<ul>
<li><p>So in Go, we don’t have keywords like <code>private</code> or <code>public</code> like other languages.</p>
</li>
<li><p>If the name starts with an <strong>uppercase letter</strong>, then it is considered as exported, meaning it can be accessed from outside the package where they’re defined.</p>
</li>
<li><p>Names starting with a <strong>lowercase letter</strong> are unexpected and private to the package.</p>
</li>
</ul>
<h3 id="heading-example">Example</h3>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Book <span class="hljs-keyword">struct</span> {    <span class="hljs-comment">// Exported struct</span>
    Title <span class="hljs-keyword">string</span>    <span class="hljs-comment">// Exported field</span>
    Author <span class="hljs-keyword">string</span>    <span class="hljs-comment">// Exported field</span>
}

<span class="hljs-keyword">type</span> car <span class="hljs-keyword">struct</span> {    <span class="hljs-comment">// Unexported struct</span>
    brand <span class="hljs-keyword">string</span>    <span class="hljs-comment">// Unexported field</span>
    isElectric <span class="hljs-keyword">bool</span>    <span class="hljs-comment">// Unexported field</span>
}
</code></pre>
<ul>
<li><p>Above we created two structs (don’t worry if you don’t know about structs. We will see it in detail in this blog below).</p>
</li>
<li><p>Here <code>Book</code> starts with an uppercase letter, meaning we can get this struct in other packages whereas <code>car</code> starts with a lowercase letter, meaning we can’t access this struct anywhere else.</p>
</li>
</ul>
<hr />
<h1 id="heading-basic-go-concepts">Basic Go Concepts</h1>
<h2 id="heading-types-and-variables">Types and Variables</h2>
<ul>
<li><p>Go is a statically typed language. This means every variable must have a type that’s known at compile time. Common types include:</p>
<ul>
<li><p><code>int</code>: Integer values</p>
</li>
<li><p><code>string</code>: Text data</p>
</li>
<li><p><code>bool</code>: Boolean values (true/false)</p>
</li>
<li><p><code>float</code>: Decimal values</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-declaring-variables">Declaring Variables</h2>
<ul>
<li>There are two ways you can declare a variable:</li>
</ul>
<ol>
<li><strong>Explicit Declaration</strong></li>
</ol>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> age <span class="hljs-keyword">int</span> = <span class="hljs-number">24</span>
<span class="hljs-keyword">var</span> name <span class="hljs-keyword">string</span> = <span class="hljs-string">"Dhruv"</span>
</code></pre>
<ol start="2">
<li><strong>Implicit Declaration</strong></li>
</ol>
<pre><code class="lang-go">age := <span class="hljs-number">24</span>
name := <span class="hljs-string">"Dhruv"</span>
</code></pre>
<ul>
<li>You can also declare with no value like this:</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> age <span class="hljs-keyword">int</span>    <span class="hljs-comment">// Defaut: 0</span>
<span class="hljs-keyword">var</span> name <span class="hljs-keyword">string</span>    <span class="hljs-comment">// Default: ""</span>
</code></pre>
<hr />
<h2 id="heading-constants">Constants</h2>
<ul>
<li><p>Constants are immutable values, which means we can’t change them once defined.</p>
</li>
<li><p>Use <code>const</code> keyword to declare constants</p>
</li>
<li><p>Why Use Constants?</p>
<ul>
<li><p>We use it to prevent accidental changes to critical values.</p>
</li>
<li><p>To improve the readability and maintainability of code</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">const</span> apiVersion = <span class="hljs-string">"v1"</span>
<span class="hljs-keyword">const</span> defaultPort = <span class="hljs-number">8080</span>
</code></pre>
<ul>
<li>You can use parentheses for multiple declarations too</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">const</span> (
    apiVersion = <span class="hljs-string">"v1"</span>
    defaultPort = <span class="hljs-number">8080</span>
)
</code></pre>
<hr />
<h2 id="heading-functions">Functions</h2>
<ul>
<li>We use <code>func</code> keyword to declare functions in Go.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">functionName</span><span class="hljs-params">()</span></span>{
    <span class="hljs-comment">// logic</span>
}
</code></pre>
<ul>
<li>You can have parameters inside parentheses</li>
</ul>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">functionName</span><span class="hljs-params">(parameter1 <span class="hljs-keyword">type</span>, parameter2 <span class="hljs-keyword">type</span>)</span></span>{
    <span class="hljs-comment">// logic</span>
}
</code></pre>
<ul>
<li>You can return from a function by defining a return type like this</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// Single value return</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">functionName</span><span class="hljs-params">()</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>   
}

<span class="hljs-comment">// For multiple value return</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">functionName</span><span class="hljs-params">()</span> <span class="hljs-title">int</span>, <span class="hljs-title">string</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, <span class="hljs-string">"Hello"</span>
}
</code></pre>
<hr />
<h2 id="heading-conditionals">Conditionals</h2>
<ul>
<li>The <code>if</code> statement is used for decision-making</li>
</ul>
<pre><code class="lang-go">marks := <span class="hljs-number">85</span>
<span class="hljs-keyword">if</span> marks &gt;= <span class="hljs-number">9</span>- {
    fmt.Println(<span class="hljs-string">"Grade: A"</span>)
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> marks &gt;= <span class="hljs-number">75</span> {
    fmt.Println(<span class="hljs-string">"Grade: B"</span>)
} <span class="hljs-keyword">else</span> {
    fmt.Println(<span class="hljs-string">"Grade: F"</span>)
}
</code></pre>
<ul>
<li>Short Statement with <code>if</code>. In this, we are first declaring <code>num</code> , and right after that we are checking the condition for it.</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> num := <span class="hljs-number">10</span>; num%<span class="hljs-number">2</span> == <span class="hljs-number">0</span> {
    fmt.Println(<span class="hljs-string">"The number is even."</span>)
} <span class="hljs-keyword">else</span> {
    fmt.Println(<span class="hljs-string">"The number is odd."</span>)
}
</code></pre>
<hr />
<h2 id="heading-loops">Loops</h2>
<ul>
<li>In Go we have only <code>for loop</code> for looping. There are different ways you can use <code>for</code> loop. Let’s see it in action</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// Basic `for` loop</span>
<span class="hljs-keyword">for</span> i:= <span class="hljs-number">0</span>; i&lt;<span class="hljs-number">5</span>; i++ {
    fmt.Println(<span class="hljs-string">"Value of i: ,"</span>, i)
}

<span class="hljs-comment">// Infinite Loop</span>
count := <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> {
    fmt.Println(<span class="hljs-string">"Looping forever"</span>)
    count++
    <span class="hljs-keyword">if</span> count == <span class="hljs-number">3</span> {
        <span class="hljs-keyword">break</span> <span class="hljs-comment">// Exists the loop</span>
    }
}

<span class="hljs-comment">// Condition Only Loop</span>
count:= <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> count &lt; <span class="hljs-number">3</span> {
    fmt.Println(<span class="hljs-string">"Count: "</span>, count)
    count++
}
</code></pre>
<hr />
<h1 id="heading-struct">Struct</h1>
<ul>
<li><p>If you come from programming languages like Javascript, Dart, or Python, you must be familiar with <code>class</code> and <code>objects</code>.</p>
</li>
<li><p>In Go we don’t have that. We use <code>struct</code> to group data together.</p>
</li>
<li><p>Let’s take an example of our CRUD API project. We need to represent a book with multiple details like a <code>title</code>, <code>id</code>, <code>name</code>, etc.</p>
</li>
<li><p>So instead of creating separate variables for each piece of data, you can use a <code>struct</code> to combine all of those into one entity.</p>
</li>
</ul>
<h2 id="heading-defining-a-struct">Defining a Struct</h2>
<ul>
<li>To define a structure, you use the <code>type</code> keyword followed by the structure name and its field. Each field has a name and a type</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Book <span class="hljs-keyword">struct</span> {
    ID <span class="hljs-keyword">string</span>
    Title <span class="hljs-keyword">string</span>
    Author <span class="hljs-keyword">string</span>
    Year <span class="hljs-keyword">int</span>
}
</code></pre>
<h2 id="heading-creating-and-using-a-struct">Creating and Using a Struct</h2>
<ul>
<li>Once we have defined a structure, we can use it to create an object and assign values to its fields</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> book1 Book    <span class="hljs-comment">// Creates an instance of `Book` struct</span>
book1.ID = <span class="hljs-string">"1"</span>    <span class="hljs-comment">// Assigns the value "1" to the ID field of struct</span>
book1.Title = <span class="hljs-string">"Maths"</span>
book1.Author = <span class="hljs-string">"Jane"</span>
book1.Year = <span class="hljs-number">2012</span>
</code></pre>
<h2 id="heading-initializing-a-struct-in-different-ways">Initializing a Struct in Different Ways</h2>
<ol>
<li><p>Using Field Names</p>
<ul>
<li>We can initialize a struct by specifying the field names and their values like below</li>
</ul>
</li>
</ol>
<pre><code class="lang-go">    book1 := Book{
        ID: <span class="hljs-string">"1"</span>
        Title: <span class="hljs-string">"Maths"</span>
        Author: <span class="hljs-string">"Jane"</span>
        Year: <span class="hljs-number">2012</span>
    }
</code></pre>
<ul>
<li>This looks clear, isn’t it?</li>
</ul>
<ol start="2">
<li><p>Without Field Names</p>
<ul>
<li>We can initialize it without field names too like this</li>
</ul>
</li>
</ol>
<pre><code class="lang-go">    book1 := Book{
         <span class="hljs-string">"1"</span>
         <span class="hljs-string">"Maths"</span>
         <span class="hljs-string">"Jane"</span>
         <span class="hljs-number">2012</span>
    }
</code></pre>
<ul>
<li>This is less readable because it relies on the order of fields.</li>
</ul>
<h2 id="heading-structs-with-methods">Structs with Methods</h2>
<ul>
<li><p>A method is a function that is attached to a specific type. This type of method initialization was new and kinda weird for me at first. Because usually we are required to create methods inside a class in other languages right? but here we create it separately and then attach it to the structure using the receiver.</p>
</li>
<li><p>Let me show you how</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Book <span class="hljs-keyword">struct</span> {
    ID <span class="hljs-keyword">string</span>
    Title <span class="hljs-keyword">string</span>
    Author <span class="hljs-keyword">string</span>
    Year <span class="hljs-keyword">int</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(b Book)</span> <span class="hljs-title">SayBookName</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"This book name is: "</span>, b.Title)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    book1 := Book{
        ID: <span class="hljs-string">"1"</span>
        Title: <span class="hljs-string">"Maths"</span>
        Author: <span class="hljs-string">"Jane"</span>
        Year: <span class="hljs-number">2012</span>
    }

    book1.SayBookName() <span class="hljs-comment">// Call the SayBookName method</span>
}
</code></pre>
<ul>
<li><p>As you can see to attach this <code>SayBookName</code> method to <code>Book</code> struct we provided receiver before the method name inside the parenthesis <code>(b Book)</code>. So Inside this file wherever any method has this receiver it will automatically get attached to this struct.</p>
</li>
<li><p>You can also nest struct inside a struct like this</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Book <span class="hljs-keyword">struct</span> {
    ID <span class="hljs-keyword">string</span>
    Title <span class="hljs-keyword">string</span>
    Author Author <span class="hljs-comment">// Nested struct</span>
    Year <span class="hljs-keyword">int</span>
}

<span class="hljs-keyword">type</span> Author <span class="hljs-keyword">struct</span> {
    FirstName <span class="hljs-keyword">string</span>
    LastName <span class="hljs-keyword">string</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
     book1 := Book{
        ID: <span class="hljs-string">"1"</span>
        Title: <span class="hljs-string">"Maths"</span>
        Author: Author{
            FirstName: <span class="hljs-string">"Jane"</span>
            LastName: <span class="hljs-string">"Doe"</span>
        }
        Year: <span class="hljs-number">2012</span>
    }
}
</code></pre>
<hr />
<h1 id="heading-slice">Slice</h1>
<ul>
<li><p>A <strong>slice</strong> in Go is a data structure used to hold a collection of elements of the same type.</p>
</li>
<li><p>Think of it as a more powerful and flexible version of an array.</p>
</li>
<li><p>While arrays have fixed sizes, slices can grow and shrink dynamically.</p>
</li>
<li><p>It’s really simple to use</p>
</li>
</ul>
<h2 id="heading-creating-slices">Creating Slices</h2>
<ol>
<li><p><strong>Using the</strong> <code>make</code> <strong>function</strong></p>
<ul>
<li>The <code>make</code> function creates a slice with a specific length and capacity.</li>
</ul>
</li>
</ol>
<pre><code class="lang-go">slice := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>) <span class="hljs-comment">// Create a slice of type int, of length 3 and capacity 5</span>
</code></pre>
<ul>
<li><p>Here length represents the number of elements currently in the slice which is 3 here: [0,0,0]</p>
</li>
<li><p>And Capacity represents the total space allocated for the slice which is (5). This means this slice can have max 5 elements in it.</p>
</li>
</ul>
<ol start="2">
<li><p><strong>Using a Slice Literal</strong></p>
<ul>
<li>We can define a slice directly with values using slice literal</li>
</ul>
</li>
</ol>
<pre><code class="lang-go">slice := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>}
</code></pre>
<h2 id="heading-adding-elements-to-a-slice">Adding Elements to a Slice</h2>
<ul>
<li>We can add elements to a any slice using <code>append</code> function.</li>
</ul>
<pre><code class="lang-go">slice := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>}
slice = <span class="hljs-built_in">append</span>(slice, <span class="hljs-number">4</span>,<span class="hljs-number">5</span>) <span class="hljs-comment">// adding 4 and 5 to the slice</span>
</code></pre>
<ul>
<li>We need to pass the slice where we want to add elements as the first parameter and then we can pass as many elements as we want after that.</li>
</ul>
<h2 id="heading-iterating-over-a-slice">Iterating Over a Slice</h2>
<ul>
<li>We use <code>for</code> loop to access elements in a slice</li>
</ul>
<pre><code class="lang-go">slice := []<span class="hljs-keyword">int</span>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>]

<span class="hljs-keyword">for</span> index, value := <span class="hljs-keyword">range</span> slice {
    fmt.Println(<span class="hljs-string">"Index: "</span>, index, <span class="hljs-string">"Value: "</span>,value)
}

<span class="hljs-keyword">for</span> _, value := <span class="hljs-keyword">range</span> slice {
    fmt.Println(<span class="hljs-string">"Value: "</span>,value)
}
</code></pre>
<h3 id="heading-range">Range</h3>
<ul>
<li><p>Here <code>range</code> the keyword is used to iterate over elements in a variety of data structures. In the above example, we use <code>range</code> to print the index and value in a slice.</p>
</li>
<li><p>We use underscore (<code>_</code>) to skip the variable if it’s not needed</p>
</li>
</ul>
<h2 id="heading-slicing-a-slice">Slicing a Slice</h2>
<ul>
<li>We can create a new slice by slicing an existing one.</li>
</ul>
<pre><code class="lang-go">slice := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>}
newSlice := slice[<span class="hljs-number">1</span>:<span class="hljs-number">3</span>] <span class="hljs-comment">// Slice from index 1 to 2 (3 is exclusive)</span>

<span class="hljs-comment">// newSlice: [2,3]</span>
</code></pre>
<h2 id="heading-length-and-capacity">Length And Capacity</h2>
<ul>
<li>Slices have both length and capacity as we saw above. To get the length and capacity of a slice we use <code>len()</code> and <code>cap()</code> functions</li>
</ul>
<pre><code class="lang-go">slice := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>}
fmt.Println(<span class="hljs-string">"Length: "</span>, <span class="hljs-built_in">len</span>(slice)) <span class="hljs-comment">// 5</span>
fmt.Println(<span class="hljs-string">"Capacity: "</span>, <span class="hljs-built_in">cap</span>(slice)) <span class="hljs-comment">// 5</span>
</code></pre>
<h2 id="heading-appending-slices">Appending Slices</h2>
<ul>
<li><p>We can add a whole new slice to an existing slice using <code>. . .</code> (unpack operator)</p>
<pre><code class="lang-go">  slice := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>}
  slice2 := []<span class="hljs-keyword">int</span> {<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>}

  combined := <span class="hljs-built_in">append</span>(slice, slice2...) <span class="hljs-comment">// [1,2,3,4,5,6,7,8]</span>
</code></pre>
</li>
</ul>
<hr />
<h1 id="heading-map">Map</h1>
<ul>
<li><p>This is another very helpful data structure in Go which is built in inside it. It stores <code>key</code> , <code>value</code> . This is similar to dictionaries in Python or hash maps in other programming languages.</p>
</li>
<li><p>Keys must be of a comparable type that is <code>string</code>, <code>int</code> and values can be of any type.</p>
</li>
<li><p>This data structure is useful, especially for lookups when the key uniquely identifies the data. In our case, it is Book ID</p>
</li>
</ul>
<h2 id="heading-declaring-and-initializing-a-map">Declaring and Initializing a Map</h2>
<ol>
<li><strong>Using</strong> <code>make</code></li>
</ol>
<pre><code class="lang-go">myMap := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>)

myMap[<span class="hljs-string">"Maths"</span>] = <span class="hljs-number">2</span>
myMap[<span class="hljs-string">"Biology"</span>] = <span class="hljs-number">3</span>
</code></pre>
<ul>
<li>Here <strong>[string]</strong> represents <code>key</code> and <strong>int</strong> represents <code>value</code></li>
</ul>
<ol start="2">
<li><p><strong>Using Map Literal</strong></p>
<ul>
<li>We can initialize and create a map in a single step like we did in struct</li>
</ul>
</li>
</ol>
<pre><code class="lang-go">myMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"Math"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Biology"</span>: <span class="hljs-number">3</span>,
}
</code></pre>
<h2 id="heading-accessing-values-in-a-map">Accessing Values in a Map</h2>
<ul>
<li>To get the value associated with a key, you have to use the map followed by the key in square brackets</li>
</ul>
<pre><code class="lang-go">myMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"Math"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Biology"</span>: <span class="hljs-number">3</span>,
}

fmt.Println(myMap[<span class="hljs-string">"Maths"</span>]) <span class="hljs-comment">// 2</span>
</code></pre>
<h2 id="heading-checking-if-a-key-exists">Checking if a Key Exists</h2>
<ul>
<li>We use the <strong>comma ok idiom</strong> to check if a key exists or not. This is very useful when we need to check if certain keys exist in a map or not. We can do that in a single line of code</li>
</ul>
<pre><code class="lang-go">myMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"Math"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Biology"</span>: <span class="hljs-number">3</span>,
}

value, ok := myMap[<span class="hljs-string">"Physics"</span>]

<span class="hljs-keyword">if</span> exists {
    fmt.Println(<span class="hljs-string">"Value: "</span>, value)
} <span class="hljs-keyword">else</span> {
    fmt.Println(<span class="hljs-string">"Key does not exist"</span>)
}
</code></pre>
<ul>
<li><code>value, exists := myMap["Physics"]</code>: ok is <code>true</code> if the key is present and <code>false</code> otherwise.</li>
</ul>
<h2 id="heading-adding-and-updating-elements">Adding and Updating Elements</h2>
<ul>
<li>It’s really easy, you just access the value using the key and add a new value or assign a different value to it</li>
</ul>
<pre><code class="lang-go">myMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"Math"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Biology"</span>: <span class="hljs-number">3</span>,
}

myMap[<span class="hljs-string">"Physics"</span>] = <span class="hljs-number">4</span> <span class="hljs-comment">// Adding new element</span>

myMap[<span class="hljs-string">"Math"</span>] = <span class="hljs-number">1</span> <span class="hljs-comment">// Updating exisitng element</span>
</code></pre>
<h2 id="heading-deleting-elements">Deleting Elements</h2>
<ul>
<li>We use <code>delete()</code> function to remove a key-value pair from the map</li>
</ul>
<pre><code class="lang-go">myMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"Math"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Biology"</span>: <span class="hljs-number">3</span>,
}

<span class="hljs-built_in">delete</span>(myMap, <span class="hljs-string">"Math"</span>) <span class="hljs-comment">// Remove the key "Math"</span>
</code></pre>
<h2 id="heading-iterating-over-a-map">Iterating Over a Map</h2>
<ul>
<li>We use again <code>for</code> loop with <code>range</code> to iterate over all key-value pairs.</li>
</ul>
<pre><code class="lang-go">myMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"Math"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Biology"</span>: <span class="hljs-number">3</span>,
}

<span class="hljs-keyword">for</span> key, value:= <span class="hljs-keyword">range</span> myMap {
    fmt.Println(<span class="hljs-string">"Key: "</span>, key, <span class="hljs-string">"Value: "</span>, value)
}
</code></pre>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li><p>I think that’s pretty much all you need to know for now. We learned lots of fundamental stuff in this article. I tried to make it as concise as possible in order to quickly grasp the underlying concepts because going into too much detail with all the theory doesn’t make sense at this point.</p>
</li>
<li><p>There is still one concept remaining which is <strong>Pointers.</strong> I wanted to cover it in this blog only but then thought it would become quite a big read so I will be explaining it in detail in the next blog.</p>
</li>
<li><p>I hope after this article you are at least comfortable with the basic stuff and syntaxes. Just practice the syntax that you find difficult to grasp. It will all make sense and your hands will then flow naturally on the keyboard afterwards.</p>
</li>
<li><p>See you in the next one, until then…</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif?auto=format,compress&amp;gif-q=60&amp;format=webm" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a>, <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a>, and <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Zero to Go Hero: Learn Go Programming with Me - Part 1]]></title><description><![CDATA[Introduction

Hello, everyone. It’s been a while since I last published anything on my blog. A lot has happened during this time, including leaving my full-time job and moving to the United States for my master's degree.

So, as my full-time job was ...]]></description><link>https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-1</link><guid isPermaLink="true">https://dhruvnakum.xyz/from-zero-to-go-hero-learn-go-programming-with-me-part-1</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[development]]></category><category><![CDATA[backend]]></category><category><![CDATA[learning]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Tue, 07 Jan 2025 21:51:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736061078296/caa153bc-3448-4397-bae5-629bbc6468a0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<ul>
<li><p>Hello, everyone. It’s been a while since I last published anything on my blog. A lot has happened during this time, including leaving my full-time job and moving to the United States for my master's degree.</p>
</li>
<li><p>So, as my full-time job was more focused on the front-end side. I always wanted to learn a backend programming language. I researched what’s going on in the software industry. And I found GO programming language which is in the trend in recent years. From what I have felt so far by learning a few things in GO till now I absolutely agree with this trend.</p>
</li>
<li><p>There are many things that makes Golang a good choice for companies to use as their backend language. And so I started learning it and as you might be knowing if are my reader that I share what I learn. Because I like to learn in public and share everything that I am learning. So here I am with a series on Learning GO.</p>
</li>
<li><p>I personally like to learn by building something. So, you and me both will be learning and building a backend system together in this series. I am so excited and looking forward to this series. I hope you get something from this. So without further a do, let’s get started.</p>
</li>
</ul>
<hr />
<h2 id="heading-why-go">Why GO?</h2>
<ul>
<li>Go, also known as Golang is a programming language by Google. The creators of the Go programming language are Robert Griesemer, Rob Pike, and Ken Thompson.</li>
</ul>
<p><img src="https://i.imgur.com/Dg8PHQF.png" alt="Understand Go in 5 minutes - Je suis un dev" class="image--center mx-auto" /></p>
<ul>
<li><p>What I like about Go is, it is very fast and it’s really easy to pick up if you know any other programming languages. It is designed to be simple, efficient, and highly scalable which makes it an excellent choice for building web servers, APIs, and large-scale systems.</p>
</li>
<li><p>I am listing down few points for you to understand why Go has become so popular among developers in recent years.</p>
<ul>
<li><p><strong>Ease of Learning:</strong></p>
<ul>
<li>It’s easy to learn as its syntax is clean and beginner friendly. It is syntactically similar to C language but it also has memory safety, garbage collection, structural typing and concurrency.</li>
</ul>
</li>
<li><p><strong>Performance:</strong></p>
<ul>
<li>As I mentioned, it is really fast, it compiles the code in seconds. This makes it perfect for web applications.</li>
</ul>
</li>
<li><p><strong>Concurrency Built in:</strong></p>
<ul>
<li>Go has powerful tools for handling multiple tasks simultaneously (more about concurrency in future blogs).</li>
</ul>
</li>
<li><p><strong>Wide Adoption</strong></p>
<ul>
<li>Companies like Google, Uber, Dropbox and many big tech giants are using Go as their primary backend language which gives programmers a sense of trust that this is something on which they can make a career and earn money.</li>
</ul>
</li>
</ul>
</li>
<li><p>I personally think that learning Go might seem a little tricky due to its syntax. But once you pick up and know syntax it’s easy to code. There are a few things that might surprise you because Go doesn’t have few things that other programming languages have. We will see it in upcoming blogs.</p>
</li>
</ul>
<hr />
<h2 id="heading-what-is-a-crud-api">What is a CRUD API?</h2>
<ul>
<li><p>If you are fresher and don’t know about CRUD then this section is for you. So CRUD basically stands for <strong>Create, Read, Update and Delete.</strong> These are you can say the base of any backend system. These operations allow users to interact with a database.</p>
</li>
<li><p>For example, you use Instagram. There are certain things you do like, Creating new Posts (<strong>Create</strong>), Reading Messages (<strong>Read</strong>), Update your profile (<strong>Update</strong>), Delete your past posts (<strong>Delete</strong>).</p>
</li>
<li><p>You see, all these are CRUD operations in action. In this series we will learn how to create these operations. We will be applying all these operations in our books example. I picked this project because this is perfect for beginners like you and me as it is straightforward yet comprehensive enough to cover key programming concepts.</p>
</li>
</ul>
<hr />
<h2 id="heading-what-will-you-learn">What Will You Learn?</h2>
<ul>
<li><p>In this series of blogs, We will learn basics and some advance stuff of Go while building a RESTful API. And by the end of this project, you’ll have practical knowledge of:</p>
<ul>
<li><p><strong>Structs</strong> and <strong>slices</strong> to organize and manipulate data.</p>
</li>
<li><p>How to use <strong>http</strong> package to setup a web server.</p>
</li>
<li><p>How to manage <strong>router.</strong></p>
</li>
<li><p>Encoding and decoding <strong>JSON</strong> to handle API requests and responses.</p>
</li>
<li><p>Writing clean, reusable, and maintainable Go code</p>
</li>
<li><p>We will also be learning advance concepts like <strong>contexts, go routines, channels, etc.</strong></p>
</li>
<li><p>and so on…</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-why-hands-on-projects-work-best">Why Hands-On Projects Work Best</h2>
<ul>
<li><p>I personally think that a person cannot learn a programming language by just reading or watching videos online. It’s not just about memorizing rules and syntax of it. It’s more about building something real. And that’s why In my blog also I try to use some real world example to make it simple to understand.</p>
</li>
<li><p>This type of learning reinforces concepts which one can immediately apply on what you’ve learned to see how it works</p>
</li>
<li><p>Also by building something while learning gives a sense of confidence that “Yes, I can do this!“</p>
</li>
<li><p>And last but not least, you can add this to your resume because that is what an employer look for in a candidate which is Practical skills.</p>
</li>
</ul>
<hr />
<p>So roll up your sleeves, fire up your favorite code editor, and let’s get started. Because this isn’t just about learning Go- It’s about empowering yourself to build things. Let’s make coding fun, practical, and rewarding.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*Ifpd_HtDiK9u6h68SZgNuA.png" alt="Golang Quickstart with Homebrew (MacOS) | by Devesu | Medium" /></p>
<hr />
<h1 id="heading-prerequisites">Prerequisites</h1>
<ul>
<li>So before we go ahead there are few things which you need to make sure you have setup on your side. Don’t worry if you are new to Go. We will go step by step. So here’s what you’ll need to get started:</li>
</ul>
<ol>
<li><p><strong>Basic Knowledge:</strong></p>
<ul>
<li>To follow along with this series you don’t need to be an expert programmer. However, a basic understanding of concepts like variables, functions, and loops will be helpful. So if you are completely new to coding, you might want to spend a little time learning these fundamentals first.</li>
</ul>
</li>
<li><p><strong>Install Go on Your Machine:</strong></p>
<ul>
<li><p>As it is not that complicated to install Go in your machine. I would like you to install by your own.</p>
</li>
<li><p>You have to just visit the <a target="_blank" href="https://go.dev/doc/install">official Go download page</a>. And grab the installer for your OS (Windows, Mac or Linux)</p>
</li>
<li><p>Then run the installer and follow the instructions. Once installed, Go should be added to your system’s PATH.</p>
</li>
<li><p>You can verify the installation by opening the terminal or command prompt and type:</p>
</li>
<li><pre><code class="lang-bash">        go version
</code></pre>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736059226413/7b2a588b-5feb-40b7-9f51-43759c32fb85.png" alt /></p>
</li>
<li><p>If you see a message like go version go1.xx.x, you are good to go!</p>
</li>
</ul>
</li>
<li><p><strong>Set Up a Code Editor</strong></p>
</li>
</ol>
<ul>
<li><p>While there are many options available online for code editor, I personally recommend VS Code for its simplicity and its excellent Go support. If you don’t have it already.</p>
<ol>
<li><p>Download and Install <a target="_blank" href="https://code.visualstudio.com/download">VS Code</a>.</p>
</li>
<li><p>Install this Go extension.</p>
</li>
</ol>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736047757052/72edb3b1-424e-4f5b-898a-9a9911ec719b.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-project-overview">Project Overview</h1>
<ul>
<li><p>Now that we are setup up, let’s see what are we gonna building. So the goal of this project is to create a simple RESTful API using Go while learning Go concepts.</p>
</li>
<li><p>This API will allow users to manage collection of books by performing CRUD operations: <strong>Create</strong>, <strong>Read</strong>, <strong>Update</strong> and <strong>Delete</strong>.</p>
</li>
</ul>
<h2 id="heading-what-is-a-restful-api">What is a RESTful API?</h2>
<ul>
<li><p>If you are completely new to this terms REST, then this section is for you. Basically a RESTful API is a way for different softwares to communicate over the web. REST stands for (Representational State Transfer). It is a design principle that make sure that APIs are simple, scalable and easy to use.</p>
</li>
<li><p>In our case, we will be building an API that uses HTTP methods like:</p>
<ul>
<li><p><strong>GET</strong> to retrieve data.</p>
</li>
<li><p><strong>POST</strong> to create new data.</p>
</li>
<li><p><strong>PUT</strong> to update existing data.</p>
</li>
<li><p><strong>DELETE</strong> to remove data.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-project-features">Project Features</h2>
<ul>
<li><p>Our API will manage list of books. So we will be having these properties in books:</p>
<ul>
<li><p><strong>ID -</strong> a unique identifier for each book.</p>
</li>
<li><p><strong>Title -</strong> the name of the book.</p>
</li>
<li><p><strong>Author -</strong> the person who wrote the book.</p>
</li>
<li><p><strong>Year -</strong> the year the book was published.</p>
</li>
</ul>
</li>
</ul>
<p>Here’s is a sneak peak at what our API will do:</p>
<ol>
<li><p><strong>Add a New Book:</strong> Accept data from the user and add book to the list.</p>
</li>
<li><p><strong>View All Books:</strong> Return a list of all books.</p>
</li>
<li><p><strong>Update a Book:</strong> Modify the details of an existing book.</p>
</li>
<li><p><strong>Delete a Book:</strong> Remove a book from the list based on its ID.</p>
</li>
</ol>
<hr />
<h1 id="heading-setting-up-your-go-project">Setting Up Your Go Project</h1>
<ul>
<li><p>Now we are ready to dive into coding. The first step is to setup your Go project.</p>
</li>
<li><p>We need to setup a proper project structure for our Go application. Following an industry standard folder structure ensures that our code is clean, modular and easy to maintain as the project grows. Here is how to do it step by step.</p>
</li>
</ul>
<hr />
<h2 id="heading-create-the-project-directory">Create the Project Directory</h2>
<ol>
<li><p>Open your terminal and navigate to the folder where you want to store your project.</p>
</li>
<li><p>Create new directory for the project:</p>
</li>
</ol>
<pre><code class="lang-bash">mkdir crud-api
<span class="hljs-built_in">cd</span> crud-api
</code></pre>
<ol start="3">
<li>Initialize a new <strong>Go module</strong>:</li>
</ol>
<pre><code class="lang-bash">go mod init github.com/red-star25/crud-api
</code></pre>
<hr />
<h2 id="heading-go-modules">Go Modules</h2>
<ul>
<li><p>If you are familiar with Javascript, Node, Flutter, then you might be knowing the file called <code>package.json</code> or <code>pubspec.yaml</code></p>
</li>
<li><p>This file is responsible for maintaining the dependencies/packages. Whether it is built-in in the language or third-party, all the dependencies with their versions are mentioned in this file.</p>
</li>
<li><p>This dependency management system is introduces in <strong>Go 1.11</strong> and made the default in <strong>Go 1.13</strong>.</p>
</li>
<li><p>So what this above <code>go mod init</code> command will do is it will create <code>go.mod</code> file in the root directory of your project.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736049300881/5943c14c-ea07-47e3-9f1b-eb0af482ad7c.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>This file specifies few things:</p>
<ol>
<li><p>The <strong>module’s name</strong>, typically repository URL or a path that identifies the codebase.</p>
</li>
<li><p><strong>Dependencies</strong> required by the project and their versions.</p>
</li>
<li><p>The <strong>Go language version</strong> used.</p>
</li>
</ol>
</li>
</ul>
<blockquote>
<p>You might have noticed that we are using GitHub repository URL for module. It is because Git repo ensures that no conflicts is there when fetching dependencies.</p>
<p>Another reason is because of versioning. Repo often follow semantic versioning using Git tags (ex., v1.0.0) which Go modules use to resolve the correct dependency version.</p>
</blockquote>
<h2 id="heading-installing-dependencies">Installing dependencies</h2>
<ul>
<li><p>In this project we will be using <code>MySql</code> as our database and also <code>Chi</code> package for managing routing. We will also be using <code>godotenv</code> for environmental configuration. Don’t worry if you don’t have any idea about it just install these packages for now and we will see what it does and how it works in upcoming blogs.</p>
</li>
<li><p>So to install packages in our go project we have <code>go get &lt;package-name&gt;</code> command.</p>
</li>
</ul>
<pre><code class="lang-bash">go get -u github.com/go-chi/chi/v5
go get -u github.com/go-sql-driver/mysql
go get -u github.com/joho/godotenv
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736055754658/2c021e09-9526-4a26-b9d7-686f66c335f5.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-folder-structure">Folder Structure</h2>
<ul>
<li><p>Go encourages simplicity, but for larger applications, it is good practice to follow a clear folder structure.</p>
</li>
<li><p>There are many tools available like: <a target="_blank" href="https://github.com/golang-standards/project-layout">Go Project Layout</a> and <a target="_blank" href="https://github.com/Melkeydev/go-blueprint">Go Blueprint</a>. Which helps you to create a base project for your Go application.</p>
</li>
<li><p>So let’s create folder structure for our project.</p>
</li>
</ul>
<pre><code class="lang-bash">crud-api/
│
├── cmd/
│   └── main/
│       └── main.go            <span class="hljs-comment"># Main entry point for the application</span>
│
├── config/
│   └── config.go              <span class="hljs-comment"># Environment and configuration management</span>
│
├── internal/
│   ├── routes/
│   │   └── routes.go          <span class="hljs-comment"># Centralized route definitions</span>
│   ├── books/                 <span class="hljs-comment"># Business logic for managing books</span>
│   │   ├── handler.go         <span class="hljs-comment"># HTTP handlers for book operations</span>
│   │   ├── model.go           <span class="hljs-comment"># Book data structure and database queries</span>
│   │   └── service.go         <span class="hljs-comment"># Business logic for books</span>
│   ├── database/              <span class="hljs-comment"># Database utilities</span>
│   │   └── db.go              <span class="hljs-comment"># Database connection logic</span>
│
├── pkg/                       <span class="hljs-comment"># Shared utility packages</span>
│   └── logger/                <span class="hljs-comment"># Logging utilities</span>
│       └── logger.go
│
├── .env                       <span class="hljs-comment"># Environment variables</span>
├── go.mod                     <span class="hljs-comment"># Go module dependencies</span>
└── go.sum                     <span class="hljs-comment"># Dependency checksums</span>
|__ .gitignore
</code></pre>
<ul>
<li>Let’s understand this structure first before we go ahead.</li>
</ul>
<h3 id="heading-top-level-files">Top Level Files</h3>
<ul>
<li><p><strong>.env</strong></p>
<ul>
<li>This contains environment specific configuration variables (e.g., database credentials, API keys).</li>
</ul>
</li>
<li><p><strong>go.mod</strong></p>
<ul>
<li>We already know what it is now</li>
</ul>
</li>
<li><p><strong>go.sum</strong></p>
<ul>
<li>Contains the checksum of dependencies to ensure integrity and consistency across builds.</li>
</ul>
</li>
<li><p><strong>.gitignore</strong></p>
<ul>
<li>Files to ignore in Git commit</li>
</ul>
</li>
</ul>
<blockquote>
<p>To add .gitignore file for Go, I recommend using <code>gitignore</code> VS code extension by <strong>CodeZombie. It will pull up Go specific .gitignore file for you</strong></p>
<p>After installing, press Cmd + Shift + P or Ctrl + Shift + P and type <strong>Add gitignore. It will ask for languages, so search for Go and hit Enter.</strong></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736055980678/6e4b05b6-88d1-46dd-afef-f67459e8089c.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Final Top Level Structure will look like this.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736056009266/3b98c23f-2e06-4d67-aa0e-674efdbed263.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-folder-and-file-structure">Folder and File Structure</h3>
<ul>
<li><p><code>cmd/main.go</code>:</p>
<ul>
<li><p>So in go you must define an entry point for the program to start. And to define it we create <code>main.go</code> file inside <code>cmd</code> folder</p>
</li>
<li><p><code>main.go</code> have main function inside which initializes the application. We setup routes, server and handle the configuration of the project here in this function.</p>
</li>
</ul>
</li>
<li><p><code>config/config.go</code>:</p>
<ul>
<li><p>In this file we load all the environment variables which is defined in <code>.env</code> .</p>
</li>
<li><p>Remember we installed <code>godotenv</code> package? This package help us reading these values. There are many other packages which does the same. I will leave it for you to search it.</p>
</li>
<li><p>So basically it defines <code>structs</code> which will hold configuration data for example, database credentials, server ports, etc. (more on <code>structs</code> later)</p>
</li>
</ul>
</li>
<li><p><code>internal/</code></p>
<ul>
<li><p>This folder holds the core business logic and internal code.</p>
</li>
<li><p>Code written inside this will not be exposed as part of the public API.</p>
</li>
</ul>
</li>
</ul>
<ol>
<li><p><code>routes/routes.go</code></p>
<ul>
<li>In this we register all our routes for API like <code>/books</code>, <code>/authors</code> which will be mapped to it’s respective handlers/functions. Again don’t worry if you don’t understand any of these term, we will be seeing it in action soon for better understanding. Just get the basic understanding for now.</li>
</ul>
</li>
<li><p><code>books/</code></p>
<ul>
<li><p>This folder handles all the business logic related to the “Books“ resource.</p>
</li>
<li><p><code>handler.go</code>:</p>
<ul>
<li><p>In this we define HTTP handlers for CRUD operations.</p>
</li>
<li><p>Ex: <code>CreateBook</code>, <code>GetBooks</code>, <code>UpdateBook</code>, <code>DeleteBook</code></p>
</li>
<li><p>Basically we have the logic of our CRUD operations for book in this file for handling HTTP requests and responses.</p>
</li>
</ul>
</li>
<li><p><code>model.go</code>:</p>
<ul>
<li><p>In this we have <code>Book</code> structure with fields like <code>ID</code>, <code>Title</code>, <code>Author</code>.</p>
</li>
<li><p>Also we implement database queries here like <code>FindAllBooks</code>, <code>SaveBook</code> etc.</p>
</li>
</ul>
</li>
<li><p><code>service.go</code>:</p>
<ul>
<li>This contains all the business rules and logic for books and it will act as a Bridge between the handler and model like validating data.</li>
</ul>
</li>
</ul>
</li>
<li><p><code>database/db.go</code>:</p>
<ul>
<li><p>As the name suggests it has the logic for handling database connection and utilities.</p>
</li>
<li><p>In this we initialize database connection.</p>
</li>
</ul>
</li>
<li><p><code>pkg/</code>:</p>
<ul>
<li><p>This folder contains code which is shared across different parts of the application or even other projects.</p>
</li>
<li><p><code>logger/logger.go</code>:</p>
<ul>
<li><p>This file implements logging logic using packages like <code>logrus</code> or <code>zap</code></p>
</li>
<li><p>It may include support for logging levels like <code>INFO</code>, <code>DEBUG</code>, <code>ERROR</code>.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736057409526/968512c8-f521-4505-a0a3-552e8bb3487a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-how-it-all-fits-together">How It All Fits Together</h3>
<ul>
<li><p>Let’s understand how all these files are connected to each other.</p>
<ul>
<li><p><code>cmd/main/main.go</code> Loads configuration from <code>config/</code></p>
</li>
<li><p>It connects to database via <code>internal/database/</code></p>
</li>
<li><p>Sets up routes using <code>internal/routes/</code></p>
</li>
<li><p>And finally starts the server.</p>
</li>
</ul>
</li>
<li><p><code>internal/books</code> handles CRUD operations for book and <code>pkg/logger</code> provides a way to log information or errors from anywhere in the project.</p>
</li>
<li><p><code>.env</code> is loaded to proved sensitive or environment specific configurations</p>
</li>
</ul>
<blockquote>
<p>This organization ensure clean separation of concerns, making the codebase scalable, maintainable and testable.</p>
</blockquote>
<ul>
<li>I know I spent a lot of time explaining folder structure but it’s a one time investment. Almost every go project will have similar kind of structure, so in future if you encounter this you will have an idea of what each part is used for.</li>
</ul>
<hr />
<h2 id="heading-configure-environment-variables">Configure Environment Variables</h2>
<ul>
<li>Go to <code>.env</code> file in the root directory and let’s add configuration values:</li>
</ul>
<pre><code class="lang-plaintext">DB_USER=root
DB_PASSWORD=crudAPI@1234
DB_HOST=127.0.0.1:3306
DB_NAME=crud_api
PORT=8080
</code></pre>
<ul>
<li>As we will be using MySQL database we need to configure variables like username, password and host value. So we mention everything inside <code>.env</code> file as we don’t want to expose these sensitive values publicly.</li>
</ul>
<hr />
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<ul>
<li><p>I will end this blog here. We learned many things about Go:</p>
<ul>
<li><p>Why Go?</p>
</li>
<li><p>What is CRUD operations?</p>
</li>
<li><p>What is RESTful APIs?</p>
</li>
<li><p>Go Modules</p>
</li>
<li><p>How to install packages in Go?</p>
</li>
<li><p>Folder Structure of Go project</p>
</li>
<li><p>Environmental variables file.</p>
</li>
</ul>
</li>
<li><p>Before we dive into coding. We first need to understand few concepts of Go. Which I will be explaining in the next blog.</p>
</li>
<li><p>I hope you like the blog and learned something from it. If you have any questions or suggestions please leave them in the comment section. I would love to answer and discuss them.</p>
</li>
<li><p>See you in the next article. Until then….</p>
</li>
</ul>
<p><img src="https://media.tenor.com/H9y5_3rPqkAAAAAM/peace-out-im-out.gif" alt="Peace Out GIFs | Tenor" class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a>, <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a>, and <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a>.</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Becoming an Expert in Flutter with Clean Architecture: The Implementation-Part 3]]></title><description><![CDATA[Introduction

Heleww there 👋🏻, welcome again or welcome if you are coming here for the first time. Thanks for clicking on this blog and taking the time to read it.

I'm writing a series on Clean Architecture in Flutter, and this is the last article...]]></description><link>https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-the-implementation-part-3</link><guid isPermaLink="true">https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-the-implementation-part-3</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[clean code]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Mon, 01 Apr 2024 03:49:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711815872474/fabff1c0-8194-42cc-88b3-f6ccda065096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<ul>
<li><p>Heleww there 👋🏻, welcome again or welcome if you are coming here for the first time. Thanks for clicking on this blog and taking the time to read it.</p>
</li>
<li><p>I'm writing a series on Clean Architecture in Flutter, and this is the last article in that series.</p>
</li>
<li><p>In <strong>Part 1</strong>, we covered the basics of Clean Architecture, what it is, and why it's important for Flutter developers or any developer to use this architecture when coding.</p>
</li>
<li><p>In <strong>Part 2</strong>, we looked at how to organize your Flutter project and build an application using Clean Architecture. We set up Data, Domain, and Presentation layers, along with Core and other necessary folders. We went through each folder, explaining its purpose and how to use it.</p>
</li>
</ul>
<hr />
<h2 id="heading-the-objective-of-part-3">The Objective of Part 3</h2>
<ul>
<li>In this blog, we are going to create two feature.</li>
</ul>
<ol>
<li><p><strong>News:</strong></p>
<ul>
<li><p>Here, we will use a dummy news API to get News.</p>
</li>
<li><p>We will also cache all the news using Hive DB, allowing users to read and interact with the app even when they are offline.</p>
</li>
</ul>
</li>
<li><p><strong>Number/Count Info:</strong></p>
<ul>
<li><p>We'll use the Numbers API. Here, we'll send a random number to the API, and it will give us an interesting fact about that number.</p>
</li>
<li><p>We'll also use Hive to cache everything for this feature.</p>
</li>
</ul>
</li>
</ol>
<ul>
<li>This blog is going to be very interesting. You'll learn a lot, not just about Clean Architecture, but also how to organize code, name things properly, and much more.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711815997353/00a37107-eb1b-4e39-aa01-000e802372fe.gif" alt class="image--center mx-auto" /></p>
<p>Are you readyyy!!!?</p>
<ul>
<li>Yes!!!? Then let's get started without any delay.</li>
</ul>
<blockquote>
<p>There is one💡BONUS for you too. So stay tuned.</p>
</blockquote>
<hr />
<h3 id="heading-setting-up-the-environment-and-project-structure">Setting up the environment and project structure</h3>
<ul>
<li>To get started clone below repository in your local machine:</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/red-star25/clean_architecture_flutter_boilerplate">https://github.com/red-star25/clean_architecture_flutter_boilerplate</a></div>
<p> </p>
<hr />
<h2 id="heading-feature-1-news">Feature 1: News</h2>
<ul>
<li>Let's create a feature called <strong>news</strong> inside <code>lib/features/</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711788266329/81bb055a-f014-40bf-98aa-df28c207b48b.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Now, let's also create sub-folders for each of these directories:</p>
<ul>
<li><p><strong>data:</strong></p>
<ul>
<li><p>datasources</p>
</li>
<li><p>models</p>
</li>
<li><p>repositories</p>
</li>
</ul>
</li>
<li><p><strong>domain:</strong></p>
<ul>
<li><p>entities</p>
</li>
<li><p>repositories</p>
</li>
<li><p>usecases</p>
</li>
</ul>
</li>
<li><p><strong>presentation</strong></p>
<ul>
<li><p>cubit</p>
</li>
<li><p>pages</p>
</li>
<li><p>widgets</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711788556375/ef989224-53d0-474b-8420-98a75d9055c1.png" alt class="image--center mx-auto" /></p>
<ul>
<li>So, we've set up the basic structure for the <strong>news</strong> feature. What's next? Let's begin with the <strong>presentation layer</strong>.</li>
</ul>
<hr />
<h3 id="heading-setting-up-routes">Setting up routes</h3>
<ul>
<li>Let's create a page named <code>news_page.dart</code> in <code>features/news/presentation/pages/</code> so we can add it to the route and get started.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> NewsPage({Key? key}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'News'</span>),
      ),
    );
  }
}
</code></pre>
<ul>
<li>To add this route go to <code>routes.dart</code> and <code>paths.dart</code> file and add below code snippets:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// paths.dart</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Paths</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> newsPage = <span class="hljs-string">'/news'</span>;
}
</code></pre>
<pre><code class="lang-dart"><span class="hljs-comment">// routes.dart</span>
<span class="hljs-keyword">final</span> router = GoRouter(
  initialLocation: Paths.newsPage,    <span class="hljs-comment">// &lt;---- Add initial route too</span>
  routes: [
    GoRoute(
      path: Paths.newsPage,
      builder: (context, state) =&gt; <span class="hljs-keyword">const</span> NewsPage(),
    ),
  ],
);
</code></pre>
<ul>
<li>We also have to update <code>app.dart</code> files' configurations.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// app.dart</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:clean_architecture_bloc/routes/routes.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> App({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> ScreenUtilInit(
      designSize: <span class="hljs-keyword">const</span> Size(<span class="hljs-number">390</span>, <span class="hljs-number">844</span>),
      builder: (_, __) =&gt; MaterialApp.router(    <span class="hljs-comment">// &lt;------</span>
        <span class="hljs-comment">// other configuration</span>
        routerConfig: router,     <span class="hljs-comment">// &lt;---- Provide our `router` as routerConfig</span>
      ),
    );
  }
}
</code></pre>
<p>Now, If we run the app you will see <em>News</em> text in AppBar</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711794907353/5b63395e-77c6-4b80-bd6c-e3cee03eb531.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-implementing-domain-layer">Implementing Domain Layer</h3>
<ul>
<li>As we know that Domain layer is the heart of the Clean Architecture. Let's start with this layer.</li>
</ul>
<h4 id="heading-news-entity">News Entity</h4>
<ul>
<li>Let's start with the entity. First we need to see what the data looks like so click on this link and analyse the data : <a target="_blank" href="https://saurav.tech/NewsAPI/everything/cnn.json">News API</a></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711795262984/cf17f943-a414-4095-a5b9-19d91fc5b2e5.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Here, we see that the main data we need is a list of <code>articles</code>, right? So, this becomes our entity because, remember, what is an Entity?</p>
<blockquote>
<p>They are like the main characters in a story. They are real-world things or concepts important to your app. For example, in an e-commerce app, entities could be <code>Product</code>, <code>Customer</code>, and <code>Order</code>.</p>
</blockquote>
</li>
<li><p>So let's create <code>news_entity</code> inside <code>features/news/domain/entities</code> folder.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsEntity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">0</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> status;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">1</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int?</span> totalResults;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">2</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;ArticlesEntity&gt;? articles;

  <span class="hljs-keyword">const</span> NewsEntity({<span class="hljs-keyword">this</span>.status, <span class="hljs-keyword">this</span>.totalResults, <span class="hljs-keyword">this</span>.articles});

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [status, totalResults, articles];
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticlesEntity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">1</span>)
  <span class="hljs-keyword">final</span> SourceEntity? source;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">2</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> author;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">3</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> title;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">4</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> description;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">5</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> url;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">6</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> urlToImage;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">7</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> publishedAt;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">8</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> content;

  <span class="hljs-keyword">const</span> ArticlesEntity(
      {<span class="hljs-keyword">this</span>.source,
      <span class="hljs-keyword">this</span>.author,
      <span class="hljs-keyword">this</span>.title,
      <span class="hljs-keyword">this</span>.description,
      <span class="hljs-keyword">this</span>.url,
      <span class="hljs-keyword">this</span>.urlToImage,
      <span class="hljs-keyword">this</span>.publishedAt,
      <span class="hljs-keyword">this</span>.content});

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [
        source,
        author,
        title,
        description,
        url,
        urlToImage,
        publishedAt,
        content
      ];
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SourceEntity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">0</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> id;
  <span class="hljs-meta">@HiveField</span>(<span class="hljs-number">1</span>)
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> name;

  <span class="hljs-keyword">const</span> SourceEntity({<span class="hljs-keyword">this</span>.id, <span class="hljs-keyword">this</span>.name});

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [id, name];
}
</code></pre>
<ul>
<li>Here were also annotating every field of our Entity with <code>HiveField()</code> because we want our news to be stored locally. If you don't have the functionality of storing data locally then you can exclude that step.</li>
</ul>
<hr />
<h4 id="heading-getnews-usecase">GetNews UseCase</h4>
<ul>
<li><p>What is the main goal of this feature? To get News from the API, right?</p>
</li>
<li><p>So that becomes our Usecase to <strong>GetNews</strong> from the API.</p>
</li>
</ul>
<blockquote>
<p><strong>Recap</strong>: Use cases <strong>represent specific actions</strong> that users can do to accomplish something in your app. They act as the <strong>bridge between</strong> what the user does and the core logic covered by entities.</p>
</blockquote>
<ul>
<li>Let's create a file <code>get_news.dart</code> inside <code>features/news/domain/usecases</code> and create GetNews use case</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GetNews</span> </span>{
  <span class="hljs-keyword">final</span> NewsRepository newsRepository;

  GetNews({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.newsRepository});

  Future&lt;Either&lt;Failure, NewsEntity&gt;&gt; call() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> newsRepository.getNews();
  }
}
</code></pre>
<ul>
<li><p>Here, we have the NewsRepository, and we're using its <code>getNews()</code> method to get data from the Data layer.</p>
</li>
<li><p>We're using <code>dartz</code> for functional programming. The return type is <strong>Either</strong>, meaning this function will return either <strong>Failure</strong> or <strong>NewsEntity</strong>. For more info, check out the <a target="_blank" href="https://pub.dev/packages/dartz">dartz package</a>.</p>
</li>
<li><p>You might see some errors because we haven't created NewsRepository yet. Let's create it now.</p>
</li>
</ul>
<hr />
<h4 id="heading-news-repository">News Repository</h4>
<ul>
<li><p>The repository in the domain layer serves as a <strong>bridge</strong> between the <strong>domain layer</strong> and the <strong>data layer</strong>. It's essentially an abstract class, with its implementation detailed in the Data layer.</p>
</li>
<li><p>Think of it as a middleman that manages data operations, allowing the domain layer to remain unaware of the specifics of data storage or retrieval. Let's go ahead and create our NewsRepository now.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRepository</span> </span>{
  Future&lt;Either&lt;Failure, NewsEntity&gt;&gt; getNews();
}
</code></pre>
<ul>
<li><p>We've finished with the Domain layer. It's straightforward, right? Not complicated at all. But that's if you've read the previous blog 😅; otherwise, it might seem hard.</p>
</li>
<li><p>Now, let's move on to the Data layer.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711800439239/0cf3dd48-fca8-45bd-a73e-e65fc2c08e72.gif" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-implementing-data-layer">Implementing Data Layer</h3>
<ul>
<li>In this layer, we have <code>datasources</code>, <code>models</code>, and <code>repositories</code>. So, what's the Data layer for again, just to quickly recap?</li>
</ul>
<blockquote>
<p>The Data layer talks to APIs, Databases, and so on, and sends data back to the Domain layer, which the Presentation layer uses to show it on the screen.</p>
</blockquote>
<ul>
<li>Let's start with the data source.</li>
</ul>
<h4 id="heading-news-remote-data-source">News Remote Data Source</h4>
<ul>
<li>Before we start the implementation we need to define the API URL inside <strong>Endpoints</strong> class.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// endpoints.dart</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Endpoints</span> </span>{
  Endpoints._();
  <span class="hljs-comment">// ...  </span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> newsBaseURL =
      <span class="hljs-string">'https://saurav.tech/NewsAPI/everything/cnn.json'</span>;
}
</code></pre>
<ul>
<li>Now create <code>news_remote_data_source.dart</code> file inside <code>features/news/data/datasources</code> directory and paste below code.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRemoteDataSource</span> </span>{
  Future&lt;Response&gt; getNews();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRemoteDataSourceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NewsRemoteDataSource</span> </span>{
  <span class="hljs-keyword">final</span> _dioClient = getIt.<span class="hljs-keyword">get</span>&lt;DioClient&gt;();

  <span class="hljs-meta">@override</span>
  Future&lt;Response&gt; getNews() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">final</span> newsResponse = <span class="hljs-keyword">await</span> _dioClient.<span class="hljs-keyword">get</span>(Endpoints.newsBaseURL);
      <span class="hljs-keyword">return</span> newsResponse;
    } <span class="hljs-keyword">on</span> DioException {
      <span class="hljs-keyword">rethrow</span>;
    }
  }
}
</code></pre>
<ul>
<li><p>First, we created an abstract Remote Data Source class and then its implementation class <code>NewsRemoteDataSourceImpl</code>.</p>
</li>
<li><p>Simply put, we are using DioClient's <code>get()</code> method to get the data and return the <strong>Response</strong> object. Nothing scary or complicated going on here.</p>
</li>
</ul>
<hr />
<h4 id="heading-news-local-data-source">News Local Data Source</h4>
<ul>
<li><p>We're also setting up offline viewing for our users, so we need to work on the Local Data source.</p>
</li>
<li><p>Before that, some setup is required.</p>
</li>
<li><p>Go to the <code>hive_helper.dart</code> class. First, we need to open a Hive box for our news feature.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HiveHelper</span> </span>{
  <span class="hljs-keyword">static</span> init() <span class="hljs-keyword">async</span> {<span class="hljs-comment">//...}</span>

  <span class="hljs-keyword">static</span> openBox() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> Hive.openBox(kNewsBox);
  }
}
</code></pre>
<ul>
<li><code>kNewsBox</code> is defined in the <code>constants.dart</code> file</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// constants.dart</span>
<span class="hljs-built_in">String</span> kNewsBox = <span class="hljs-string">'newsBox'</span>;
</code></pre>
<ul>
<li>Now that we have opened the box let's get the box by defining the <code>getNewsBox()</code> function</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HiveHelper</span> </span>{
  <span class="hljs-keyword">static</span> init() <span class="hljs-keyword">async</span> {<span class="hljs-comment">//...}</span>
  <span class="hljs-keyword">static</span> openBox() <span class="hljs-keyword">async</span> {<span class="hljs-comment">//...}</span>

  <span class="hljs-keyword">static</span> Box&lt;<span class="hljs-built_in">dynamic</span>&gt; getNewsBox() {
    <span class="hljs-keyword">return</span> Hive.box(kNewsBox);
  }
}
</code></pre>
<ul>
<li>Great!! Now we are good to go. Let's create <code>news_local_data_source.dart</code> file and paste code below.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsLocalDataSource</span> </span>{
  Future&lt;<span class="hljs-keyword">void</span>&gt; cacheArticles({<span class="hljs-keyword">required</span> <span class="hljs-built_in">List</span>&lt;ArticleModel&gt;? articles});
  Future&lt;<span class="hljs-built_in">List</span>&lt;ArticleModel&gt;?&gt; getNews();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsLocalDataSourceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NewsLocalDataSource</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">List</span>&lt;ArticleModel&gt;?&gt; getNews() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">final</span> newsData = HiveHelper.getNewsBox().<span class="hljs-keyword">get</span>(kNewsBox);

    <span class="hljs-keyword">if</span> (newsData != <span class="hljs-keyword">null</span>) {
      <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;ArticleModel&gt; newsList = [];
      <span class="hljs-keyword">for</span> (ArticleModel item <span class="hljs-keyword">in</span> newsData) {
        newsList.add(ArticleModel.fromJson(item.toJson()));
      }
      <span class="hljs-keyword">return</span> newsList;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
  }

  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-keyword">void</span>&gt; cacheArticles({<span class="hljs-keyword">required</span> <span class="hljs-built_in">List</span>&lt;ArticleModel&gt;? articles}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> HiveHelper.getNewsBox().put(
        kNewsBox,
        articles,
      );
    } <span class="hljs-keyword">on</span> HiveError {
      <span class="hljs-keyword">throw</span> CacheException();
    }
  }
}
</code></pre>
<ul>
<li><p>We start by creating an abstract class, similar to what we did in RemoteDataSource, where we define two primary methods required for caching.</p>
<ul>
<li><p><strong>getNews</strong>: This method retrieves all the news from the box and converts it into ArticleModel format. If the box is empty, it returns <code>null</code>.</p>
</li>
<li><p><strong>cacheNews</strong>: After successfully getting data from the remote data source API, we use this method to save the latest news in local db.</p>
</li>
</ul>
</li>
<li><p>You must be seeing an error with <strong>ArticleModel</strong>, let's go ahead and create ArticleModel in the models directory.</p>
</li>
</ul>
<hr />
<h4 id="heading-newsmodel">NewsModel</h4>
<ul>
<li><p>A quick recap of what Model is:</p>
<blockquote>
<p>Models act as blueprints for real-world things in our code, like News in this case, right?</p>
<p>They're quite similar to Entities, and we actually make every model class inherit from its corresponding Entities. The main difference is that models include functions like <code>fromJson</code> , <code>toJson</code> ,<code>toMap</code>, etc. These functions help the data layer convert information/data from third-party APIs or databases into a format we can use.</p>
</blockquote>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:clean_architecture_bloc/features/news/domain/entities/news_entity.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:hive/hive.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'news_model.g.dart'</span>;

<span class="hljs-meta">@HiveType</span>(typeId: <span class="hljs-number">1</span>)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsModel</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NewsEntity</span> </span>{
  <span class="hljs-keyword">const</span> NewsModel({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.status,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.totalResults,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.articles,
  });

  <span class="hljs-keyword">factory</span> NewsModel.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) {
    <span class="hljs-keyword">return</span> NewsModel(
      status: json[<span class="hljs-string">'status'</span>],
      totalResults: json[<span class="hljs-string">'totalResults'</span>],
      articles: (json[<span class="hljs-string">'articles'</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">List</span>)
          .map((e) =&gt; ArticleModel.fromJson(e))
          .toList(),
    );
  }

  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-string">'status'</span>: status,
      <span class="hljs-string">'totalResults'</span>: totalResults,
      <span class="hljs-string">'articles'</span>:
          articles?.cast&lt;ArticleModel&gt;().map((e) =&gt; e.toJson()).toList(),
    };
  }
}

<span class="hljs-meta">@HiveType</span>(typeId: <span class="hljs-number">2</span>)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleModel</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ArticlesEntity</span> </span>{
  <span class="hljs-keyword">const</span> ArticleModel({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.source,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.author,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.title,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.description,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.url,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.urlToImage,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.publishedAt,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.content,
  });

  <span class="hljs-keyword">factory</span> ArticleModel.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) {
    <span class="hljs-keyword">return</span> ArticleModel(
      source:
          json[<span class="hljs-string">'source'</span>] != <span class="hljs-keyword">null</span> ? SourceModel.fromJson(json[<span class="hljs-string">'source'</span>]) : <span class="hljs-keyword">null</span>,
      author: json[<span class="hljs-string">'author'</span>],
      title: json[<span class="hljs-string">'title'</span>],
      description: json[<span class="hljs-string">'description'</span>],
      url: json[<span class="hljs-string">'url'</span>],
      urlToImage: json[<span class="hljs-string">'urlToImage'</span>],
      publishedAt: json[<span class="hljs-string">'publishedAt'</span>],
      content: json[<span class="hljs-string">'content'</span>],
    );
  }

  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-string">'source'</span>: (source <span class="hljs-keyword">as</span> SourceModel).toJson(),
      <span class="hljs-string">'author'</span>: author,
      <span class="hljs-string">'title'</span>: title,
      <span class="hljs-string">'description'</span>: description,
      <span class="hljs-string">'url'</span>: url,
      <span class="hljs-string">'urlToImage'</span>: urlToImage,
      <span class="hljs-string">'publishedAt'</span>: publishedAt,
      <span class="hljs-string">'content'</span>: content,
    };
  }
}

<span class="hljs-meta">@HiveType</span>(typeId: <span class="hljs-number">3</span>)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SourceModel</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">SourceEntity</span> </span>{
  <span class="hljs-keyword">const</span> SourceModel({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.id,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.name,
  });

  <span class="hljs-keyword">factory</span> SourceModel.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) {
    <span class="hljs-keyword">return</span> SourceModel(
      id: json[<span class="hljs-string">'id'</span>],
      name: json[<span class="hljs-string">'name'</span>],
    );
  }

  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-string">'id'</span>: id,
      <span class="hljs-string">'name'</span>: name,
    };
  }
}
</code></pre>
<ul>
<li><p>Here were also annotating the classes with <code>@HiveType()</code> because we want our NewsModels to be stored in our NewsBox. This helps <code>hive_generator</code> to generate Adapter classes for each models which we need to register.</p>
</li>
<li><p>Now, import this model class into the datasources class where we were getting errors, and everything should work fine.</p>
</li>
</ul>
<blockquote>
<p>If you're seeing an error in the <code>part 'news_model.g.dart'</code> line, you can fix it by running the <code>flutter pub run build_runner build</code> command in the terminal. This will generate the HiveAdapter class.</p>
</blockquote>
<ul>
<li>After generating the file head over to <strong>HiveHelper</strong> class and <strong>Register</strong> those <strong>Adapters</strong></li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HiveHelper</span> </span>{
  <span class="hljs-keyword">static</span> init() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> Hive.initFlutter();
    Hive.registerAdapter(NewsModelAdapter());
    Hive.registerAdapter(ArticleModelAdapter());
    Hive.registerAdapter(SourceModelAdapter());
    <span class="hljs-keyword">await</span> openBox();
  }
  <span class="hljs-comment">//...</span>
}
</code></pre>
<hr />
<h4 id="heading-newsrepository">NewsRepository</h4>
<ul>
<li><p>A quick recape again for Data layers repository:</p>
<blockquote>
<p>It directly communicates with either the Remote or Local data sources and sends the data back to the Domain layer. It also handles any errors that occur while accessing data, ensuring these errors are managed in a way that the rest of the app can easily deal with.</p>
</blockquote>
</li>
<li><p>Remember we created abstract Repository class inside Domain. We implement every method of it in this class.</p>
</li>
<li><p>Create <code>news_repository_impl.dart</code> file and paste below code in it:</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRepositoryImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NewsRepository</span> </span>{
  <span class="hljs-keyword">final</span> NewsRemoteDataSource remoteDataSource;
  <span class="hljs-keyword">final</span> NewsLocalDataSource localDataSource;

  <span class="hljs-keyword">final</span> networkInfo = getIt.<span class="hljs-keyword">get</span>&lt;NetworkInfo&gt;();

  NewsRepositoryImpl(
      {<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.remoteDataSource, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.localDataSource});

  <span class="hljs-meta">@override</span>
  Future&lt;Either&lt;Failure, NewsModel&gt;&gt; getNews() <span class="hljs-keyword">async</span> {
    <span class="hljs-comment">// Checking the connectivity</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> networkInfo.isConnected!) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Getting News from API</span>
        <span class="hljs-keyword">final</span> remoteNews = <span class="hljs-keyword">await</span> remoteDataSource.getNews();
        <span class="hljs-keyword">final</span> newsModel = NewsModel.fromJson(remoteNews.data);
        <span class="hljs-comment">// Storing news in HiveBox</span>
        <span class="hljs-keyword">await</span> localDataSource.cacheArticles(
          articles: newsModel.articles?.cast&lt;ArticleModel&gt;(),
        );
        <span class="hljs-keyword">return</span> Right(newsModel);
      } <span class="hljs-keyword">on</span> DioException <span class="hljs-keyword">catch</span> (e) {
        <span class="hljs-keyword">final</span> errorMessage = DioExceptions.fromDioError(e);
        <span class="hljs-keyword">return</span> Left(ServerFailure(errorMessage: errorMessage.message));
      }
    } <span class="hljs-keyword">else</span> {
     <span class="hljs-comment">// If no internet, getting data from database</span>
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">final</span> localNews = <span class="hljs-keyword">await</span> localDataSource.getNews();
        <span class="hljs-keyword">if</span> (localNews != <span class="hljs-keyword">null</span>) {
          <span class="hljs-keyword">return</span> Right(
            NewsModel(
              status: <span class="hljs-string">'200'</span>,
              totalResults: localNews.length,
              articles: localNews,
            ),
          );
        } <span class="hljs-keyword">else</span> {
          <span class="hljs-keyword">throw</span> CacheException();
        }
      } <span class="hljs-keyword">on</span> HiveError <span class="hljs-keyword">catch</span> (_) {
        <span class="hljs-keyword">return</span> Left(HiveFailure(errorMessage: _.message));
      } <span class="hljs-keyword">on</span> CacheException <span class="hljs-keyword">catch</span> (_) {
        <span class="hljs-keyword">return</span> Left(CacheFailure(errorMessage: <span class="hljs-string">'No News Found'</span>));
      }
    }
  }
}
</code></pre>
<ul>
<li>Great !! We have successfully completed <strong>Data</strong> layer implementation. Now it's time to implement UI and get the data.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711800373581/31c5d7b7-1361-4c18-bf25-f5b08f5000b1.gif" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-implementing-presentation-layer">Implementing Presentation Layer</h3>
<ul>
<li>Now that we have implemented everything related to data. Let's now get that data by calling our <strong>GetNews</strong> usecase in our cubit.</li>
</ul>
<h4 id="heading-news-cubit">News Cubit</h4>
<ul>
<li><p>Create two files inside Cubit directory:</p>
<ul>
<li><p><code>news_cubit.dart</code>: Where we will write all the business logic</p>
</li>
<li><p><code>news_state.dart</code> : For managing states like, Success, Failure, etc.</p>
</li>
</ul>
</li>
<li><p>For now we need only two states, NewsSuccess and NewsError. Let's create it.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// news_state.dart</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsSuccess</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseState</span> </span>{
  <span class="hljs-keyword">final</span> NewsEntity newsEntity;

  NewsSuccess({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.newsEntity});

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [newsEntity];
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseState</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> message;

  NewsError({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.message});

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [message];
}
</code></pre>
<ul>
<li>Also let's write the business logic for getting News inside NewsCubit</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsCubit</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Cubit</span>&lt;<span class="hljs-title">BaseState</span>&gt; </span>{
  NewsCubit() : <span class="hljs-keyword">super</span>(StateInitial());

  <span class="hljs-keyword">final</span> getNewsUserCase = getIt.<span class="hljs-keyword">get</span>&lt;GetNews&gt;();

  Future&lt;<span class="hljs-keyword">void</span>&gt; getNews() <span class="hljs-keyword">async</span> {
    emit(StateLoading());
    <span class="hljs-keyword">final</span> result = <span class="hljs-keyword">await</span> getNewsUserCase.call();
    result.fold(
      (failure) =&gt; emit(NewsError(message: failure.errorMessage)),
      (news) =&gt; emit(NewsSuccess(newsEntity: news)),
    );
  }
}
</code></pre>
<ul>
<li><p>We just call the <code>call()</code> method from GetNews use case. If we get data, we show NewsSuccess; if not, we show NewsError with an error message.</p>
</li>
<li><p>Before designing our UI, we need to add this Cubit to our NewsPage. Go to <code>routes.dart</code> and use BlocProvider to wrap around NewsPage.</p>
</li>
<li><p>We also need to run the <code>getNews()</code> function right when the page loads.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> router = GoRouter(
  initialLocation: Paths.newsPage,
  routes: [
    GoRoute(
      path: Paths.newsPage,
      builder: (context, state) =&gt; BlocProvider(
        create: (context) =&gt; NewsCubit()..getNews(),
        child: <span class="hljs-keyword">const</span> NewsPage(),
      ),
    ),
  ],
);
</code></pre>
<hr />
<h4 id="heading-newspage">NewsPage</h4>
<ul>
<li>Let's design our news page now.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> NewsPage({Key? key}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'News'</span>),
      ),
      body: BlocBuilder&lt;NewsCubit, BaseState&gt;(
        builder: (context, state) {
          <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> NewsSuccess) {
            <span class="hljs-keyword">return</span> Padding(
              padding: EdgeInsets.all(<span class="hljs-number">8.</span>r),
              child: RefreshIndicator(
                onRefresh: () <span class="hljs-keyword">async</span> =&gt;
                    <span class="hljs-keyword">await</span> context.read&lt;NewsCubit&gt;().getNews(),
                child: ListView.separated(
                  itemCount: state.newsEntity.articles?.length ?? <span class="hljs-number">0</span>,
                  separatorBuilder: (BuildContext context, <span class="hljs-built_in">int</span> index) {
                    <span class="hljs-keyword">return</span> Divider(
                      height: <span class="hljs-number">30.</span>h,
                      color: Colors.grey.withOpacity(<span class="hljs-number">.3</span>),
                      endIndent: <span class="hljs-number">30</span>,
                      indent: <span class="hljs-number">30</span>,
                    );
                  },
                  itemBuilder: (BuildContext context, <span class="hljs-built_in">int</span> index) {
                    <span class="hljs-keyword">final</span> news = state.newsEntity.articles?[index];
                    <span class="hljs-keyword">return</span> NewsItem(news: news);
                  },
                ),
              ),
            );
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> NewsError) {
            <span class="hljs-keyword">return</span> Center(
              child: Text(state.message),
            );
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> StateLoading) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> Center(
              child: CircularProgressIndicator(),
            );
          }
          <span class="hljs-keyword">return</span> Container();
        },
      ),
    );
  }
}
</code></pre>
<ul>
<li>As you can see, we return the Widget based on the state we receive. Let's create a NewsItem widget inside the <code>widget</code> directory.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsItem</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> NewsItem({
    <span class="hljs-keyword">super</span>.key,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.news,
  });

  <span class="hljs-keyword">final</span> ArticlesEntity? news;

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Column(
      children: [
        Align(
          alignment: Alignment.topLeft,
          child: Text(
            news?.source?.name ?? <span class="hljs-string">''</span>,
            style: Theme.of(context)
                .textTheme
                .titleMedium
                ?.copyWith(fontWeight: FontWeight.bold),
          ),
        ),
        SizedBox(height: <span class="hljs-number">5.</span>h),
        Row(
          children: [
            Image.network(
              news?.urlToImage ?? <span class="hljs-string">''</span>,
              height: <span class="hljs-number">100.</span>h,
              width: <span class="hljs-number">100.</span>h,
              fit: BoxFit.contain,
            ),
            SizedBox(width: <span class="hljs-number">20.</span>w),
            Expanded(
                child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  news?.title ?? <span class="hljs-string">''</span>,
                  textAlign: TextAlign.justify,
                ),
                SizedBox(height: <span class="hljs-number">10.</span>h),
                Text(
                  news?.author ?? <span class="hljs-string">''</span>,
                  style: Theme.of(context)
                      .textTheme
                      .bodySmall
                      ?.copyWith(color: Colors.grey),
                ),
                Text(
                  news?.publishedAt ?? <span class="hljs-string">''</span>,
                  style: Theme.of(context)
                      .textTheme
                      .bodySmall
                      ?.copyWith(color: Colors.grey),
                ),
              ],
            )),
          ],
        ),
      ],
    );
  }
}
</code></pre>
<blockquote>
<p>⚠️ I am not going deep into explaining the UI as it is very simple and require basic understanding of Flutter.</p>
</blockquote>
<hr />
<h3 id="heading-injecting-dependencies-using-getit">Injecting Dependencies using GetIt</h3>
<ul>
<li><p>Before we start the app to check the news data, we first need to register the classes we've created. This way, we can use them anywhere without having to initialize them over and over.</p>
</li>
<li><p>We do this using GetIt. You should already have a <code>service_locator.dart</code> file in the base project. Go there and add the following code to set it up.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> getIt = GetIt.instance;

Future&lt;<span class="hljs-keyword">void</span>&gt; setupLocator() <span class="hljs-keyword">async</span> {
  <span class="hljs-keyword">await</span> HiveHelper.init();

  getIt.registerLazySingleton&lt;Dio&gt;(() =&gt; Dio());
  getIt.registerLazySingleton&lt;DioClient&gt;(() =&gt; DioClient(getIt&lt;Dio&gt;()));

  getIt.registerLazySingleton&lt;NetworkInfo&gt;(
      () =&gt; NetworkInfoImpl(DataConnectionChecker()));

  <span class="hljs-comment">// ----------- News -----------</span>
  getIt.registerSingleton&lt;NewsRepository&gt;(NewsRepositoryImpl(
    localDataSource: NewsLocalDataSourceImpl(),
    remoteDataSource: NewsRemoteDataSourceImpl(),
  ));
  getIt.registerSingleton&lt;GetNews&gt;(
      GetNews(newsRepository: getIt.<span class="hljs-keyword">get</span>&lt;NewsRepository&gt;()));
}
</code></pre>
<hr />
<h3 id="heading-running-the-application">Running the Application</h3>
<ul>
<li>Finger crossed 🤞🏻...let's run the application 🫣</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711802102445/a59010f6-e8c4-4a6e-a766-ba4f603570c5.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711801988771/276ea81a-b537-41bd-8147-44892b10d0ef.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Ohkay 😅 sorry for the overacting there. But hey, we made it....</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711802175440/50b87e82-52dc-40fe-94a1-aa85249c6145.gif" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-feature-2-counter">Feature 2: Counter</h2>
<ul>
<li><p>I just realized this blog has gotten really long. So, I'll share the repository where these two features are implemented.</p>
</li>
<li><p>But before that, I highly recommend trying to implement the feature on your own. It will help you understand everything better.</p>
</li>
<li><p>Here's the repo link:</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/red-star25/clean_architecture_flutter">https://github.com/red-star25/clean_architecture_flutter</a></div>
<p> </p>
<hr />
<h2 id="heading-the-bonus">The BONUS</h2>
<ul>
<li><p>Oh yes, THE BONUS, right? I've got you covered.</p>
</li>
<li><p>The bonus is, as you might have noticed, creating the feature with all these folders and files can take a lot of time. You can save time by using the <a target="_blank" href="https://pub.dev/packages/mason_cli">mason_cli</a> package.</p>
</li>
<li><p>After setting it up, you can visit <a target="_blank" href="https://brickhub.dev/">brickhub.dev</a> where you'll find many templates for Clean Architecture like this one.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://brickhub.dev/bricks/clean_architecture_folders/0.1.0+3">https://brickhub.dev/bricks/clean_architecture_folders/0.1.0+3</a></div>
<p> </p>
<ul>
<li>After adding the brick in your system you just have to now hit this command :</li>
</ul>
<pre><code class="lang-dart">mason add clean_architecture_folders
</code></pre>
<p>And Voila!!! you will have the feature ready for you:</p>
<pre><code class="lang-dart">.
├── home
│   ├── data
│   │   ├── datasources
│   │   ├── models
│   │   └── repositories
│   ├── domain
│   │   ├── entities
│   │   ├── usecase
│   │   └── repositories
│   └── presentation
└── ...
</code></pre>
<ul>
<li>Let me know in the comments if you're interested in a blog about Mason. I'll definitely write one because it's a very useful tool, not just for this situation but for many others as well.</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><p>This is it! We have successfully completed the Clean Architecture series together.</p>
</li>
<li><p>I hope this series has added value to your knowledge. If it did, I would love to hear your thoughts/feedback in the comments.</p>
</li>
<li><p>Thank you for supporting the series. There are many more things on the way. To get notified when the new blog is posted, subscribe to my newsletter.</p>
</li>
<li><p>See you in the next blog, until then...</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711803084752/aa266313-a315-41a8-9538-8ff4370577fb.gif" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a>, <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a>, and <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a>.</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Becoming an Expert in Flutter with Clean Architecture: Part 2]]></title><description><![CDATA[Introduction
Hey there 👋🏻 Welcome back to part two of the journey through Clean Architecture, or a big hello if you're here for the first time. I'm really glad you decided to check out this article, and I promise you won't regret it.


Recap of the...]]></description><link>https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-part-2</link><guid isPermaLink="true">https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-part-2</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[software development]]></category><category><![CDATA[Clean Architecture]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[architecture]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Tue, 26 Mar 2024 05:10:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711353757734/8a15d4f6-3322-4d57-9b08-a5ad9547f864.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hey there 👋🏻 Welcome back to part two of the journey through Clean Architecture, or a big hello if you're here for the first time. I'm really glad you decided to check out this article, and I promise you won't regret it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710953199389/58cef8a2-f407-47ff-ba9d-c823974093f1.gif" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-recap-of-the-first-article">Recap of the first article</h2>
<p>If you're new to this Clean Architecture series, I've already covered the basics of Clean Architecture. Here's a quick summary:</p>
<ul>
<li><p>We started by talking about why Clean Architecture is important.</p>
</li>
<li><p>Next, we looked at the three main parts of Clean Architecture:</p>
<ul>
<li><p><strong>Presentation</strong></p>
</li>
<li><p><strong>Domain</strong></p>
</li>
<li><p><strong>Data layer</strong></p>
</li>
</ul>
</li>
<li><p>We explored each layer in detail, explaining what each one does, and using examples to help understand their roles and responsibilities.</p>
</li>
<li><p>If you have not checked it yet go ahead and take a look at it:</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-a-comprehensive-guide">https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-a-comprehensive-guide</a></div>
<p> </p>
<blockquote>
<p>Pre-requisites: The pre-requisite for reading this article is above blog on Clean Architecure and a basic knowledge of Flutter.</p>
</blockquote>
<hr />
<h2 id="heading-in-this-article">In this article...</h2>
<ul>
<li><p>This blog I will show you how to organize your project's folders for Clean Architecture, based on what we covered in the first article.</p>
</li>
<li><p>We'll use <a target="_blank" href="https://pub.dev/packages/flutter_bloc">flutter_bloc</a> for managing states. If you're not familiar with Bloc, it's okay. You can use any state management method that fits with Clean Architecture.</p>
</li>
<li><p>So, without further ado, let's dive in.</p>
</li>
</ul>
<hr />
<h2 id="heading-project-setup">Project Setup</h2>
<ul>
<li><p>First of all, go to a directory of your choice and hit the below command in termial to create a flutter project.</p>
<pre><code class="lang-bash">  flutter create my_app
</code></pre>
</li>
<li><p>After creating a project let's now go ahead and add a required dependency. Head over to <code>pubspec.yaml</code> and add the below dependencies:</p>
</li>
</ul>
<pre><code class="lang-dart">dependencies: 
    data_connection_checker_tv: ^<span class="hljs-number">0.3</span><span class="hljs-number">.5</span>-nullsafety <span class="hljs-comment">// For checking internet connectivity </span>
    flutter_screenutil: ^<span class="hljs-number">5.9</span><span class="hljs-number">.0</span> <span class="hljs-comment">// For creating responsive </span>
    dio: ^<span class="hljs-number">5.4</span><span class="hljs-number">.1</span> <span class="hljs-comment">// For making http requests </span>
    get_it: ^<span class="hljs-number">7.6</span><span class="hljs-number">.7</span> <span class="hljs-comment">// For dependency injection </span>
    logger: ^<span class="hljs-number">2.1</span><span class="hljs-number">.0</span> <span class="hljs-comment">// For logging debug </span>
    flutter_bloc: ^<span class="hljs-number">8.1</span><span class="hljs-number">.4</span> <span class="hljs-comment">// For State management </span>
    equatable: ^<span class="hljs-number">2.0</span><span class="hljs-number">.5</span> <span class="hljs-comment">// For value based equality </span>
    dartz: ^<span class="hljs-number">0.10</span><span class="hljs-number">.1</span> <span class="hljs-comment">// For functional programming </span>
    go_router: ^<span class="hljs-number">13.2</span><span class="hljs-number">.0</span> <span class="hljs-comment">// For managing routing </span>
    hive: ^<span class="hljs-number">2.2</span><span class="hljs-number">.3</span> <span class="hljs-comment">// For local data storage </span>
    hive_flutter: ^<span class="hljs-number">1.1</span><span class="hljs-number">.0</span> <span class="hljs-comment">// For local data storage</span>
</code></pre>
<p>Also, add following dependencies in <code>dev_dependencies</code>:</p>
<pre><code class="lang-dart">dev_dependencies: 
    flutter_test: 
    flutter hive_generator: ^<span class="hljs-number">2.0</span><span class="hljs-number">.1</span> <span class="hljs-comment">// For generating hive classes </span>
    build_runner: ^<span class="hljs-number">2.4</span><span class="hljs-number">.8</span> <span class="hljs-comment">// For code generation</span>
</code></pre>
<ul>
<li>Okay so now that we are all set let's see what the folder structure looks like of Clean Architecture.</li>
</ul>
<hr />
<h2 id="heading-folder-structure">Folder Structure</h2>
<ul>
<li><p>In Clean Architecture, the primary two folders contain most of the necessary components are:</p>
<ul>
<li><p><strong>core</strong></p>
</li>
<li><p><strong>features</strong></p>
</li>
</ul>
</li>
<li><p>We also have other folders like <code>common_widgets</code>, <code>di</code>, <code>routes</code>, and a <code>app</code> folder. Let's create each folder under the lib folder.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711004265535/fb9f44da-6b0d-4441-848d-647240fc111c.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Let's look at what each folder does:</li>
</ul>
<hr />
<h4 id="heading-features">features</h4>
<ul>
<li><p>This is the core of Clean Architecture, where we put into practice everything discussed in the first blog about Clean Architecture.</p>
</li>
<li><p>Okay so let's understand this. Our app has different parts, right? Like Login, SignUp, Home, Settings, Product, etc.</p>
</li>
<li><p>For each part, we make a separate folder in a feature folder.</p>
</li>
<li><p>Inside this, we create <strong>three</strong> more folders:</p>
<ul>
<li><p><strong>data,</strong></p>
</li>
<li><p><strong>domain, and</strong></p>
</li>
<li><p><strong>presentation</strong></p>
</li>
</ul>
</li>
<li><p>Yes, these folders are exactly what we talked about in the previous blog.</p>
</li>
<li><p>So as an example, Let's make a feature called <strong>Counter</strong>.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711274907399/b6e7b67d-55b7-48e2-b76d-cf6e854d5410.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Cool! Now let's dive deep into each folder and understand how to implement it.</p>
</li>
</ul>
<h5 id="heading-domain"><strong>domain</strong></h5>
<ul>
<li><p>From what we learned in the last article, this layer is at the heart of Clean Architecture. It acts as a bridge between the <em>presentation</em> and <em>data</em> layers.</p>
</li>
<li><p>We'll make 3 more folders named <strong>Entities, Repositories, and Usecases</strong> and create respectively <code>.dart</code> files in them.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711274851772/58b999ed-e52e-4046-a6ce-d39c36873c1d.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>⚠️ Note: Since we'll be coding everything in the next article, I won't be showing all the code with you right now otherwise this blog will become lengthy. So Let's just focus on the structure and how it will look.</p>
</blockquote>
<pre><code class="lang-dart"><span class="hljs-comment">// counter_entity.dart</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterEntity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{
    <span class="hljs-comment">//...    </span>
}
</code></pre>
<ul>
<li>So, for the counter feature, we've created <strong>CounterEntity</strong> which we'll be using across the presentation layer.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// counter_repository.dart</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterInfoRepository</span> </span>{
    <span class="hljs-comment">//...</span>
}
</code></pre>
<ul>
<li>Remember the Repository from the last blog? It's an abstract class that acts as a blueprint for our data layer's repository. So in CounterRepository, we will be creating all the abstract functions.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// get_count_info.dart</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GetCountInfo</span> </span>{
  <span class="hljs-keyword">final</span> CounterInfoRepository counterRepository;

  GetCountInfo({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.counterRepository});

  <span class="hljs-comment">//...</span>
}
</code></pre>
<ul>
<li>Lastly, there's the GetCountInfo use case. It's basically a specific action the user will do, like getting info on a number.</li>
</ul>
<hr />
<h5 id="heading-data"><strong>data</strong></h5>
<ul>
<li><p>The data layer in Clean Architecture manages the app's data. It links the repository layer, which serves as the entry point, to actual data sources such as databases, files, and APIs.</p>
</li>
<li><p>We'll make three folders we're already familiar with: <strong>datasources, models,</strong> and <strong>repositories</strong>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711277472981/1dc6223f-7fd0-4903-ab15-85cf62d2c03a.png" alt class="image--center mx-auto" /></p>
<ul>
<li>In the <code>datasources</code> folder, we have two files. One is for remote data, which uses <code>DioClient</code> to get the data and send it to the repository. The other is for local data, which uses <code>Hive</code> to cache, save, and get the data. Let's take a look at the code.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// counter_local_data_source.dart</span>

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterLocalDataSource</span> </span>{
  Future&lt;<span class="hljs-keyword">void</span>&gt; cacheCountInfo({<span class="hljs-keyword">required</span> CounterModel? counterToCache});
  Future&lt;CounterModel?&gt; getCountInfo();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterLocalDataSourceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CounterLocalDataSource</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;CounterModel?&gt; getCountInfo() <span class="hljs-keyword">async</span> {<span class="hljs-comment">//...}</span>

  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-keyword">void</span>&gt; cacheCountInfo({<span class="hljs-keyword">required</span> CounterModel? counterToCache}) <span class="hljs-keyword">async</span> {<span class="hljs-comment">//...}</span>
}
</code></pre>
<pre><code class="lang-dart"><span class="hljs-comment">// counter_remote_data_source.dart</span>

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterRemoteDataSource</span> </span>{
  Future&lt;Response&gt; getCounterInfo({<span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> count});
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterRemoteDataSourceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CounterRemoteDataSource</span> </span>{
  <span class="hljs-keyword">final</span> _dioClient = getIt.<span class="hljs-keyword">get</span>&lt;DioClient&gt;();

  <span class="hljs-meta">@override</span>
  Future&lt;Response&gt; getCounterInfo({<span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> count}) <span class="hljs-keyword">async</span> {<span class="hljs-comment">//..}</span>
}
</code></pre>
<ul>
<li>Now let's create a model class. Models act like blueprints for things in real life within our code. We use them to turn raw data from these data sources into a format that Dart can understand and use where needed.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterModel</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CounterEntity</span> </span>{
  <span class="hljs-keyword">const</span> CounterModel({<span class="hljs-keyword">required</span> <span class="hljs-keyword">super</span>.countInfo});

  <span class="hljs-keyword">factory</span> CounterModel.fromJson({<span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> json}) {
    <span class="hljs-keyword">return</span> CounterModel(countInfo: json);
  }

  CounterModel copyWith({<span class="hljs-built_in">String?</span> countInfo}) {
    <span class="hljs-keyword">return</span> CounterModel(countInfo: countInfo ?? <span class="hljs-keyword">this</span>.countInfo);
  }
}
</code></pre>
<ul>
<li>Lastly, create a repository implementation class. This class will handle all the business logic, from fetching data from data sources, converting it into a model, and then passing it to the domain layer with proper error handling.</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterRepositoryImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CounterInfoRepository</span> </span>{
  <span class="hljs-keyword">final</span> CounterRemoteDataSource remoteDataSource;
  <span class="hljs-keyword">final</span> CounterLocalDataSource localDataSource;
  <span class="hljs-keyword">final</span> networkInfo = getIt.<span class="hljs-keyword">get</span>&lt;NetworkInfo&gt;();

  CounterRepositoryImpl({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.remoteDataSource,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.localDataSource,
  });

  <span class="hljs-meta">@override</span>
  Future&lt;Either&lt;Failure, CounterModel&gt;&gt; getCountInfo(
      {<span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> count}) <span class="hljs-keyword">async</span> {<span class="hljs-comment">//...} </span>
  }
}
</code></pre>
<ul>
<li>As you can see, we have expanded our repository implementation class with the domain layer's repository and implemented the method <code>getCountInfo</code>.</li>
</ul>
<hr />
<h5 id="heading-presentation"><strong>presentation</strong></h5>
<ul>
<li>This layer connects your user to the application. It mainly consists of three parts: <strong>business logic, pages,</strong> and <strong>widgets.</strong> Let's create those folders and files.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711278788933/a1a12a0a-4beb-4e11-bc7e-5c99e616ad5d.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>If you're using flutter_bloc, put your business logic in the cubit/bloc folder like I did. If not, you can make a folder for your own state management.</p>
</li>
<li><p>And in pages and widgets, it's simple, you code all the UI-related stuff</p>
</li>
</ul>
<hr />
<p>So, that was the main part of the Clean Architecture which we just finished. Now, let's go through the responsibilities and uses of other folders one by one.</p>
<hr />
<h4 id="heading-app">app</h4>
<ul>
<li><p>This folder contains the entry widget of the application. We use this app widget in the <code>main.dart</code> file's <code>runApp()</code> function.</p>
</li>
<li><p>So, make a file named <code>app.dart</code> and copy the following code into it:</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> App({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> ScreenUtilInit(
      designSize: <span class="hljs-keyword">const</span> Size(<span class="hljs-number">390</span>, <span class="hljs-number">844</span>),
      builder: (_, __) =&gt; MaterialApp.router(
        debugShowCheckedModeBanner: <span class="hljs-keyword">false</span>,
        locale: <span class="hljs-keyword">const</span> Locale(<span class="hljs-string">'en'</span>, <span class="hljs-string">'US'</span>),
        title: kAppName,
        theme: themeData,
        routerConfig: router,
      ),
    );
  }
}
</code></pre>
<ul>
<li>Here, we've defined all the basic elements such as <code>routing</code>, <code>localisation</code>, <code>screen utils</code>, and more. Simple, right? Okay, let's move forward now.</li>
</ul>
<hr />
<h4 id="heading-commonwidget">common_widget</h4>
<ul>
<li><p>It's where we put all the widgets that are used all over our app. These are the widgets we need to use again and again on different pages and in different situations.</p>
</li>
<li><p>To make it clearer, some widgets in this folder are the <strong>Appbar</strong>, which gives a consistent top navigation bar on different screens; the <strong>BottomNavBar</strong>, which lets users easily move between the main features of the app from the bottom of the screen; and the <strong>Drawer</strong>, a menu that slides out and can be accessed from many places in the app.</p>
</li>
</ul>
<hr />
<blockquote>
<p><strong>⚠️ NOTE:</strong> I won't paste the entire code of each file here because some files have a lot of lines. You'll be able to access this code at the end of this blog. So stay tuned and let's keep going.</p>
</blockquote>
<h4 id="heading-core">core</h4>
<ul>
<li><p><em>As the name suggests, this section defines all the core functionalities of the application, such as</em><code>constants</code>, <code>network</code>, <code>local db</code>, etc. Let's now break down this folder and see what it contains:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711007018924/3eb795ac-9564-41cd-bd3e-2c39c905dddf.png" alt class="image--center mx-auto" /></p>
<h5 id="heading-base-optional"><strong>base (optional):</strong></h5>
</li>
<li><p>I made this folder because I'm using <strong>flutter_bloc</strong> in this project for managing states.</p>
</li>
<li><p>This folder contains a bloc class called <code>base_bloc.dart</code> and a state class called <code>base_state.dart</code>.</p>
</li>
<li><p>Essentially, this will serve as the foundation for all the cubits we plan to create.</p>
<pre><code class="lang-dart">  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BaseBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BlocObserver</span> </span>{
    <span class="hljs-meta">@override</span>
    <span class="hljs-keyword">void</span> onEvent(Bloc bloc, <span class="hljs-built_in">Object?</span> event) {
      <span class="hljs-keyword">super</span>.onEvent(bloc, event);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-keyword">void</span> onTransition(Bloc bloc, Transition transition) {
      <span class="hljs-keyword">super</span>.onTransition(bloc, transition);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-keyword">void</span> onError(BlocBase bloc, <span class="hljs-built_in">Object</span> error, StackTrace stackTrace) {
      <span class="hljs-keyword">super</span>.onError(bloc, error, stackTrace);
    }
  }
</code></pre>
</li>
<li><p>Similarly, we will create a state class where we will define common states as shown below:</p>
<pre><code class="lang-dart">  <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BaseState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{}

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StateInitial</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseState</span> </span>{
    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [];
  }
  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StateOnSuccess</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseState</span> </span>{
    <span class="hljs-keyword">final</span> T response;
    StateOnSuccess(<span class="hljs-keyword">this</span>.response);
    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [];
  }

  <span class="hljs-comment">//...define other state</span>
</code></pre>
<hr />
<h5 id="heading-connection"><strong>connection</strong></h5>
</li>
<li><p>Remember we added the <code>data_connection_checker_tv</code> package in <code>pubspec.yaml</code>? We'll create a class named <code>NetworkInfo</code> to handle connectivity logic and use this package.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfo</span> </span>{
  Future&lt;<span class="hljs-built_in">bool</span>&gt;? <span class="hljs-keyword">get</span> isConnected;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfoImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NetworkInfo</span> </span>{
  <span class="hljs-keyword">final</span> DataConnectionChecker connectionChecker;

  NetworkInfoImpl(<span class="hljs-keyword">this</span>.connectionChecker);

  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">bool</span>&gt; <span class="hljs-keyword">get</span> isConnected =&gt; connectionChecker.hasConnection;
}
</code></pre>
<ul>
<li>Whenever we need to check device connectivity, we can use <code>isConnected</code>, a boolean.</li>
</ul>
<blockquote>
<p>💡Use Case: You will see the use of this in the Data Layer's Repository Implementation.</p>
</blockquote>
<hr />
<h5 id="heading-constant"><strong>Constant</strong></h5>
<ul>
<li>In this section, we set up all the app-level constants such as colors, text, themes, fonts, and more.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711184608705/98f8a134-ce97-4aa4-8e73-cf0073313957.png" alt class="image--center mx-auto" /></p>
<hr />
<h5 id="heading-errors"><strong>Errors</strong></h5>
<ul>
<li><p>In this folder, we have two files</p>
</li>
<li><p><strong>Exception -</strong> This file lists the Remote and Local errors we could encounter when making API calls or fetching local data</p>
<pre><code class="lang-dart">  <span class="hljs-comment">// exceptions.dart</span>
  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServerException</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Exception</span></span>{}
  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CacheException</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Exception</span></span>{}
</code></pre>
</li>
<li><p><strong>Failure -</strong> We're using <code>dartz</code>, a package for functional programming, so we'll return two things from a function. If you're not familiar with functional programming, don't worry. We'll cover what we need to know in the next article.</p>
</li>
<li><p>We have different types of failures, such as <em>ServerFailure</em>, <em>CacheFailure</em>, <em>NetworkFailure</em>, and more. We define all these types in this class and use them.</p>
</li>
</ul>
<pre><code class="lang-dart">    <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Failure</span> </span>{
      <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> errorMessage;
      <span class="hljs-keyword">const</span> Failure({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.errorMessage});
    }

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServerFailure</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Failure</span> </span>{
      ServerFailure({<span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> errorMessage})
          : <span class="hljs-keyword">super</span>(errorMessage: errorMessage);
    }

    <span class="hljs-comment">//..Other failures</span>
</code></pre>
<hr />
<h5 id="heading-local"><strong>local</strong></h5>
<ul>
<li>We use <strong>Hive</strong> to store and fetch local data. We've created a helper class to manage all the local database-related tasks.</li>
</ul>
<ul>
<li><pre><code class="lang-dart">        <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HiveHelper</span> </span>{
          <span class="hljs-keyword">static</span> init() <span class="hljs-keyword">async</span> {
            <span class="hljs-keyword">await</span> Hive.initFlutter();
            <span class="hljs-comment">// register hive adapters</span>
            <span class="hljs-keyword">await</span> openBox();
          }

          <span class="hljs-keyword">static</span> openBox() <span class="hljs-keyword">async</span> {
               <span class="hljs-comment">// Open Hive boxes</span>
          }
        }
</code></pre>
</li>
</ul>
<hr />
<h4 id="heading-network"><strong>network</strong></h4>
<ul>
<li><p>In this folder, we define everything related to networking such as network <em>Clients</em>, <em>Endpoints</em>, and <em>Interceptors</em>. We have created three folders for these:</p>
<ul>
<li><p><strong>client</strong></p>
</li>
<li><p><strong>endpoints</strong></p>
</li>
<li><p><strong>interceptors</strong></p>
</li>
</ul>
</li>
<li><p>Let's explore each one and learn what they do.</p>
<hr />
<h5 id="heading-client"><strong>client</strong></h5>
<ul>
<li>In this folder, we will define our <strong>dio client</strong> which we will be using to make API calls.</li>
</ul>
</li>
</ul>
<pre><code class="lang-dart">    <span class="hljs-comment">// dio_client.dart</span>

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DioClient</span> </span>{
      <span class="hljs-comment">// dio instance</span>
      <span class="hljs-keyword">final</span> Dio _dio;

      <span class="hljs-comment">// injecting dio instance</span>
      DioClient(<span class="hljs-keyword">this</span>._dio) {
        _dio
          ..options.baseUrl = Endpoints.baseUrl
          ..options.connectTimeout =
              <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(milliseconds: Endpoints.connectionTimeout)
          ..options.receiveTimeout =
              <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(milliseconds: Endpoints.receiveTimeout)
          ..options.responseType = ResponseType.json
          ..interceptors.add(DioInterceptor())
          ..interceptors.add(LogInterceptor());
      }

      Future&lt;Response&gt; <span class="hljs-keyword">get</span>(...) <span class="hljs-keyword">async</span> {...}

      Future&lt;Response&gt; post(...) <span class="hljs-keyword">async</span> {...}

      Future&lt;Response&gt; put(...) <span class="hljs-keyword">async</span> {...}

      Future&lt;Response&gt; delete(...) <span class="hljs-keyword">async</span> {...}
    }
</code></pre>
<ul>
<li><p>We've made a <strong>DioClient</strong> class that includes all the necessary network calls such as <code>get</code>, <code>post</code>, <code>put</code>, <code>delete</code>.</p>
</li>
<li><p>There's also a <code>dioexception</code> class for managing network errors and sending formatted messages to the user.</p>
</li>
<li><p>Let's create it too.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// dio_exceptions.dart</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DioExceptions</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Exception</span> </span>{
  <span class="hljs-keyword">late</span> <span class="hljs-built_in">String</span> message;

  DioExceptions.fromDioError(DioException dioError) {
    <span class="hljs-keyword">switch</span> (dioError.type) {
      <span class="hljs-keyword">case</span> DioExceptionType.cancel:
        message = <span class="hljs-string">"Request to API server was cancelled"</span>;
        <span class="hljs-keyword">break</span>;
      <span class="hljs-comment">// Handle other DioError</span>
  }

  <span class="hljs-built_in">String</span> _handleError(<span class="hljs-built_in">int?</span> statusCode, <span class="hljs-built_in">dynamic</span> error) {
    <span class="hljs-keyword">switch</span> (statusCode) {
      <span class="hljs-keyword">case</span> <span class="hljs-number">400</span>:
        <span class="hljs-keyword">return</span> error[<span class="hljs-string">'message'</span>] ?? <span class="hljs-string">'Bad request'</span>;
      <span class="hljs-comment">// Handle other status code</span>
    }
  }
}
</code></pre>
<hr />
<h5 id="heading-interceptor"><strong>Interceptor</strong></h5>
<ul>
<li><p>The app often includes an authentication module where users register and log in.</p>
</li>
<li><p>To prevent unauthorized access, we require an access token for every request. Instead of manually adding the access token to every API call, which can be time-consuming, we use an interceptor to handle it automatically.</p>
</li>
<li><p>For more information about interceptors, read this blog:</p>
</li>
<li><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://dhruvnakum.xyz/networking-in-flutter-interceptors">https://dhruvnakum.xyz/networking-in-flutter-interceptors</a></div>
<p> </p>
</li>
<li><p>Let's create a <strong>Dio Interceptor</strong></p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DioInterceptor</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">InterceptorsWrapper</span> </span>{
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onRequest(
      RequestOptions options, RequestInterceptorHandler handler) <span class="hljs-keyword">async</span> {
    log(<span class="hljs-string">"Request[<span class="hljs-subst">${options.method}</span>] =&gt; PATH: <span class="hljs-subst">${options.path}</span>"</span>);
    <span class="hljs-comment">// Pass accessToken in header of every request</span>
    <span class="hljs-keyword">super</span>.onRequest(options, handler);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onResponse(Response response, ResponseInterceptorHandler handler) {
    log(<span class="hljs-string">"Response Status Code: [<span class="hljs-subst">$response</span>]"</span>);
    <span class="hljs-keyword">super</span>.onResponse(response, handler);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onError(DioException err, ErrorInterceptorHandler handler) {
    log(<span class="hljs-string">"Error[<span class="hljs-subst">${err.response?.statusCode}</span>] =&gt; PATH: <span class="hljs-subst">${err.requestOptions.path}</span>"</span>);
    <span class="hljs-keyword">super</span>.onError(err, handler);
  }
}
</code></pre>
<ul>
<li>Now to use this, visit our <strong>DioClient</strong> class**.** There you will see we added this interceptor.</li>
</ul>
<hr />
<h5 id="heading-endpoints"><strong>Endpoints</strong></h5>
<ul>
<li><p>In a production app, we'll have many APIs to work with. To organize all the API URLs and their endpoints, we create a separate class called <em>Endpoints</em>. This way, we can easily access the base URL and API endpoints.</p>
</li>
<li><p>Let's create it.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Endpoints</span> </span>{
  Endpoints._();

  <span class="hljs-comment">// base url</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> baseUrl = <span class="hljs-string">""</span>;
  <span class="hljs-comment">// receiveTimeout</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">int</span> receiveTimeout = <span class="hljs-number">150000</span>;
  <span class="hljs-comment">// connectTimeout</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">int</span> connectionTimeout = <span class="hljs-number">15000</span>;

  <span class="hljs-comment">// endpoints</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> login = <span class="hljs-string">"<span class="hljs-subst">$baseUrl</span>/login"</span>;
}
</code></pre>
<p>We've finally finished the <strong>core</strong> folder. I hope you now understand what's inside each folder and their responsibilities.</p>
<p>Let's move on and explore the other folders.</p>
<hr />
<h4 id="heading-di-dependency-injection">DI (Dependency Injection)</h4>
<ul>
<li><p>Dependency injection is a way to organize your code so that a class gets its dependencies from somewhere else instead of making them itself. This means your class doesn't have to set up these dependencies; they are given to it by something called an injector.</p>
</li>
<li><p>If you want to learn more about dependency injection, you can check this blog as it will explain to you from the core what is DI and why we need it.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://dhruvnakum.xyz/master-the-art-of-dependency-injection">https://dhruvnakum.xyz/master-the-art-of-dependency-injection</a></div>
<p> </p>
<ul>
<li><p>In the context of Clean Architecture, we've made classes like DioClient, NetworkInfo, Hive, etc. Instead of creating a new instance of these classes every time, we inject them at the start of the app and use the same instance everywhere in the app.</p>
</li>
<li><p>Later, we'll add more components like Repository, Data sources, Usecases, etc. We'll inject these into our business logic too, which is why we use dependency injection.</p>
</li>
<li><p>For Flutter, there's a package called <a target="_blank" href="https://pub.dev/packages/get_it"><strong>get_it</strong></a> that helps with this.</p>
</li>
<li><p>Remember the <strong>di</strong> folder in the lib folder? We'll create a <code>service_locator.dart</code> class there to set this up.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> getIt = GetIt.instance;

Future&lt;<span class="hljs-keyword">void</span>&gt; setupLocator() <span class="hljs-keyword">async</span> {
  <span class="hljs-keyword">await</span> HiveHelper.init();

  getIt.registerLazySingleton&lt;Dio&gt;(() =&gt; Dio());
  getIt.registerLazySingleton&lt;DioClient&gt;(() =&gt; DioClient(getIt&lt;Dio&gt;()));

  getIt.registerLazySingleton&lt;NetworkInfo&gt;(
      () =&gt; NetworkInfoImpl(DataConnectionChecker()));
}
</code></pre>
<ul>
<li>Now whenever we want to use any of these we use it like this:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> dioClient = getIt.<span class="hljs-keyword">get</span>&lt;DioClient&gt;();
</code></pre>
<p>That's it. As simple as that.</p>
<hr />
<h4 id="heading-routes">routes</h4>
<ul>
<li><p>We use the <a target="_blank" href="https://pub.dev/packages/go_router">go_router</a> package for routing in Flutter. It makes navigating between screens easy by using URLs.</p>
</li>
<li><p>We'll make a <code>path.dart</code> file to list all the paths used in the app.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Paths</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> loginPage = <span class="hljs-string">'/login'</span>;
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> homePage = <span class="hljs-string">'/home'</span>;
}
</code></pre>
<ul>
<li>Now let's create <code>routes.dart</code> file where will define <code>router</code> for our application:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> router = GoRouter(
  initialLocation: Paths.login,
  routes: [
    GoRoute(
      path: Paths.login,
      builder: (context, state) =&gt; <span class="hljs-keyword">const</span> LoginPage(),
    ),
    GoRoute(
      path: Paths.home,
      builder: (context, state) =&gt; <span class="hljs-keyword">const</span> HomePage(),
    ),
  ],
);
</code></pre>
<ul>
<li>We pass this <code>router</code> in MaterialApp.router() 's <code>routeConfig</code> parameter like this</li>
</ul>
<pre><code class="lang-dart">MaterialApp.router(
        <span class="hljs-comment">// other config</span>
        routerConfig: router,
),
</code></pre>
<hr />
<h4 id="heading-maindart">main.dart</h4>
<ul>
<li><p><code>main.dart</code> is the starting point of the application.</p>
</li>
<li><p>Here, we set up a logger for debugging, decide the app's orientation, and adjust other settings before the app runs.</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> logger = Logger();

Future&lt;<span class="hljs-keyword">void</span>&gt; main() <span class="hljs-keyword">async</span> {
  runZonedGuarded(
    () <span class="hljs-keyword">async</span> {
      WidgetsFlutterBinding.ensureInitialized();
      <span class="hljs-keyword">await</span> setupLocator();

      service.SystemChrome.setPreferredOrientations(
          [service.DeviceOrientation.portraitUp]).then((_) {
        runApp(<span class="hljs-keyword">const</span> App());
      });
    },
    (error, stackTrace) =&gt; logger.e(error.toString()),
  );
}
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><p>We talked about setting up Flutter project folders for Clean Architecture, including project setup, dependencies, and how to organize folders for core, features, and other key parts.</p>
</li>
<li><p>We discussed the domain, data, and presentation layers, highlighting their role in Clean Architecture.</p>
</li>
<li><p>We explored managing states with flutter_bloc, how to set up dependencies, and how to build a responsive and easy-to-maintain app structure.</p>
</li>
<li><p>We also covered dependency injection, routing, and essential features like networking and error handling, giving a full guide on applying Clean Architecture in Flutter projects.</p>
</li>
</ul>
<hr />
<h2 id="heading-in-the-next-blog">In the next blog...</h2>
<ul>
<li><p>We've gone through everything important about Clean Architecture, from the basic ideas and uses to organizing the project.</p>
</li>
<li><p>Now, it's time to start coding, isn't it?</p>
</li>
<li><p>In the next article, the last one in this Clean Architecture series, we'll build an app from the ground up using Clean Architecture concepts.</p>
</li>
</ul>
<hr />
<h2 id="heading-oh-still-here">Oh still here!!!!</h2>
<ul>
<li><p>If you've read this far, I hope you enjoyed it and learned something. If you did, I'd love to hear your thoughts and would appreciate a like to encourage me to write more articles like this.</p>
</li>
<li><p>We'll meet again in the next article. Until then...</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711355952334/13188edc-eff2-4c17-bde0-d21dcbb29c04.gif" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a>, <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a>, and <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a>.</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Becoming an Expert in Flutter with Clean Architecture: A Comprehensive Guide]]></title><description><![CDATA[Introduction
Hey there! 👋 Thank you so much for stopping by and taking the time to read this blog 😃

Okay so, picture this: You're about to go on an exciting adventure 🛣️ – not across towering mountains or through jungles, but across the vast and ...]]></description><link>https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-a-comprehensive-guide</link><guid isPermaLink="true">https://dhruvnakum.xyz/becoming-an-expert-in-flutter-with-clean-architecture-a-comprehensive-guide</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[Clean Architecture]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Developer]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Dhruv Nakum]]></dc:creator><pubDate>Wed, 20 Mar 2024 04:43:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710844103664/cb016085-d06f-476a-9d69-30bfda07b3e1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Hey there! 👋 Thank you so much for stopping by and taking the time to read this blog 😃</p>
<ul>
<li><p>Okay so, picture this: You're about to go on an exciting adventure 🛣️ – not across towering mountains or through jungles, but across the vast and vibrant landscape of software development 🧑🏻‍💻. And the coolest part? You get to be the master architect of this digital realm🌐!</p>
</li>
<li><p>Now, close your eyes 🫣 (well, not literally, because you need to read this 🙃). Picture yourself building a fancy treehouse in your backyard. You start with a strong foundation, right? That's your <strong>Clean Architecture</strong> – the strong base that holds everything together.</p>
</li>
<li><p>But what exactly is Clean Architecture 🤔? Think of it as the blueprint for your software. It's all about keeping things neat and tidy, like organizing your toys into different boxes. Each box has its own purpose, and they all work together.</p>
</li>
<li><p>But why should you care about Clean Architecture 🤷🏻‍♂️? Well, imagine you're on a quest to build the coolest app ever. Without Clean Architecture, it's like setting off on an adventure without a map – you'll get lost in messy code and tangled dependencies.</p>
</li>
<li><p>But don't worry, my friend! Clean Architecture is here to help you on this epic journey. By following its principles, you can tackle any coding challenges ⚔️, slay dragons (bugs 🐞), and emerge victorious as a coding hero 😎!</p>
</li>
<li><p>So Grab your swords (uh, I mean keyboards ⌨️) – it's time to embark on this thrilling journey!</p>
</li>
</ul>
<hr />
<h1 id="heading-introduction-to-clean-architecture"><strong>Introduction to Clean Architecture</strong></h1>
<blockquote>
<p>💡 Just so you know, the brain behind Clean Architecture is none other than Uncle Bob (Robert C. Martin). You've probably heard of him!</p>
</blockquote>
<p><img src="https://4.bp.blogspot.com/-jcrrXuZVvb4/VuEBngY7SXI/AAAAAAAAK8c/HweGw5zA5Gs/s1600/Robert_Martin-nobull.jpg" alt="Adventures in Automation: Uncle Bob Martin: The Agile Manifesto, 15 years  later" class="image--center mx-auto" /></p>
<ul>
<li><p>So according to Uncle Bob, Clean Architecture is a software architectural pattern that focuses on the <strong>Separation of Concerns</strong> which means your code will be separated into different modules.</p>
</li>
<li><p>This way, if one part of the code needs to change, it won't affect other parts, making it easier to maintain and update.</p>
</li>
<li><p>At its heart, Clean Architecture is all about arranging code in a way that makes it <strong>flexible</strong>, <strong>scalable</strong>, and <strong>easy to maintain</strong>. It offers a set of rules and ideas for organizing software, making sure that the important stuff (like business logic) doesn't get mixed up with things like how data is stored or how it's shown to users.</p>
</li>
<li><p>This separation helps keep our code clean and tidy, making it easier to work with and adapt as our projects grow.</p>
</li>
</ul>
<hr />
<h1 id="heading-understanding-the-layers">Understanding The Layers</h1>
<p>There are mainly three different layers. Each has its own specific responsibilities.</p>
<ul>
<li><p>Presentation Layer</p>
</li>
<li><p>Domain Layer</p>
</li>
<li><p>Data Layer</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710591792515/9b475db2-d119-4d45-adb2-52380d0335d9.png" alt class="image--center mx-auto" /></p>
<p>  Let's understand each layer one by one now.</p>
</li>
</ul>
<h3 id="heading-presentation-layer">Presentation Layer</h3>
<p>Okay so, this layer is the interface between your user and the application. It is responsible for handling user interactions like clicking a button, navigating through screens, etc and presenting information to the user in a way that is clear and visually appealing.</p>
<ul>
<li><p>In Flutter, the presentation layer typically consists of :</p>
<ul>
<li><p><strong>Pages</strong></p>
</li>
<li><p><strong>UI Components such as Widgets</strong> and</p>
</li>
<li><p><strong>Business Logic</strong></p>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710593059066/f91d42a6-7492-40cf-9235-223e30a7875c.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-pages">Pages</h4>
<ul>
<li><p>As the name suggests, this represents the various screens or pages of the applications. They define the layout and structure of the user interface and are responsible for arranging <strong>UI widgets</strong> in a meaningful way.</p>
</li>
<li><p>Pages often listen for user input and interact with the <strong>business logic</strong> to update the UI accordingly.</p>
</li>
</ul>
<hr />
<h4 id="heading-widgets">Widgets</h4>
<ul>
<li><p>These are the building blocks of the user interface in Flutter.</p>
</li>
<li><p>Widgets are responsible for rendering visual elements on the screen, such as buttons, text fields, and images.</p>
</li>
<li><p>Widgets combine how UI elements look and behave, making it simple to build complex user interfaces.</p>
</li>
</ul>
<hr />
<h4 id="heading-business-logic">Business Logic</h4>
<ul>
<li><p>The business Logic Component acts as a bridge between the views and the underlying business logic.</p>
</li>
<li><p>They handle user input, trigger actions in response to user interactions, and update the views with the latest data from the <strong>domain layer</strong>.</p>
</li>
<li><p>This separates the visual part of the app from the business logic, making it simpler to test and keep up to date.</p>
</li>
<li><p>In Flutter, we basically implement the state management of our choice here. For example, Bloc, Riverpod, Mobx, etc.</p>
</li>
</ul>
<p>Let's update the diagram</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710600654508/80c27494-55d8-4eac-813e-85fbb85df32d.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>To sum up,</p>
<p>The presentation layer acts as the bridge between users and the app. It deals with user inputs, shows information, and includes UI widgets and views in Flutter apps. This setup keeps the visual parts and business logic separate, making testing and updates easier.</p>
</blockquote>
<hr />
<h3 id="heading-domain-layer">Domain Layer</h3>
<p>Clean architecture is an architectural pattern that puts the focus on <strong>Domain</strong>. And that's why it is a <strong>Domain Centric Architecture.</strong> It's the core layer of Clean architecture and serves as the heart of the application.</p>
<p>This layer interacts with two different layers:</p>
<ul>
<li><p><strong>Presentation Layer:</strong></p>
<ul>
<li><p>The presentation layer handles user input and provides data for display which it gets from the domain layer.</p>
</li>
<li><p>This interaction ensures that the presentation layer remains focused on the user interface while the domain layer handles the core business logic of the application.</p>
</li>
</ul>
</li>
<li><p><strong>Data Layer:</strong></p>
<ul>
<li><p>The domain layer also interacts with the data layer to retrieve and persist data.</p>
</li>
<li><p>This interaction ensures that the domain layer remains independent of specific data sources (like remote and local data sources), allowing it to focus on business logic without being tightly coupled to external data sources.</p>
</li>
</ul>
</li>
</ul>
<p>Domain Layer typically consists of:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710601521542/cc2525f9-3895-4e3c-b487-3ef78d5663c7.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-entities">Entities</h4>
<ul>
<li><p>Entities in Clean Architecture are like the main characters in a story. Think of entities as real-world things or ideas relevant to your application. In an e-commerce application, entities might be <code>Product</code>, <code>Customer</code>, and <code>Order</code>.</p>
</li>
<li><p>Entities don't just hold data. They also define the rules and behaviours that control that data. For example, a <code>Product</code> entity might have properties like <code>name</code>, <code>price</code>, and <code>stockLevel</code>, along with <strong>methods</strong> to calculate discounts or check if there's enough inventory.</p>
</li>
<li><p>Entities should not be tied to any specific database, framework, or UI. This makes your code more adaptable and reusable across different implementations.</p>
</li>
<li><p>Let's see an Example of News app, what do you think the entity would be, Article right, so here is how ArticleEntity will look like:</p>
</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticlesEntity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> author;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> title;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> description;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> url;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> urlToImage;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> publishedAt;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> content;

  <span class="hljs-keyword">const</span> ArticlesEntity(
    {
      <span class="hljs-keyword">this</span>.author,
      <span class="hljs-keyword">this</span>.title,
      <span class="hljs-keyword">this</span>.description,
      <span class="hljs-keyword">this</span>.url,
      <span class="hljs-keyword">this</span>.urlToImage,
      <span class="hljs-keyword">this</span>.publishedAt,
      <span class="hljs-keyword">this</span>.content
    }
);

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object?</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [author,title,description,url,urlToImage,publishedAt,content];
}
</code></pre>
<hr />
<h4 id="heading-use-cases"><strong>Use Cases</strong></h4>
<ul>
<li><p>Use cases <strong>represent specific actions</strong> that users can perform to achieve something within your application. They serve as the <strong>bridge between</strong> the user's action and the domain logic encapsulated by entities.</p>
</li>
<li><p>Use cases describe functionality from the user's perspective, For example, <code>Create a new task</code> or <code>Search for completed tasks</code>, <code>Login</code>, <code>Sign up</code>, etc.</p>
</li>
<li><p>Use cases typically take inputs from the presentation layer (e.g., user form data) and return outputs representing the results of the domain operations (e.g., success/failure messages, updated data).</p>
</li>
<li><p>Let me give you an example so that you will have a clear understanding.</p>
</li>
</ul>
<p><strong>(Example) Imagine Use Cases as Waiters in a Restaurant</strong></p>
<blockquote>
<p><strong>User (Customer):</strong> You (the user) want something specific in the restaurant (the application).</p>
<p><strong>Use Case (Waiter):</strong> The waiter takes your order (the user's action, like "Create a new task").</p>
<p><strong>Domain (Kitchen):</strong> The waiter relays the order to the kitchen (the domain logic) where the cooks (entities) prepare your food.</p>
<p><strong>Presentation (Menu):</strong> The menu (presentation layer) doesn't cook the food, but it shows you what you can order (available actions).</p>
<p><strong>Inputs &amp; Outputs:</strong> You tell the waiter what you want (input), and the waiter brings you your food (output, like a success message or updated task).</p>
</blockquote>
<hr />
<h4 id="heading-repository-interfaceabstract-class">Repository (Interface/Abstract Class)</h4>
<ul>
<li><p>A repository acts as a <strong>bridge</strong> between the <strong>domain layer</strong> and the <strong>data layer</strong>. Think of it as a middleman responsible for handling data operations without the domain layer needing to know the specific details of how data is stored or retrieved.</p>
</li>
<li><p>Example:</p>
<ul>
<li><p>Imagine you're a librarian (the repository).</p>
</li>
<li><p>Your job is to manage the books (data) in the library (data layer) and provide them to the readers (domain layer) when they need them.</p>
</li>
<li><p>You know where each book is located and how to get it, but the readers don't need to know these details. They just tell you which book they want, and you take care of the rest.</p>
</li>
</ul>
</li>
<li><p>So all in all, Repositories hide the details of how data is stored and retrieved from the domain layer.</p>
</li>
</ul>
<p>Now, let's update the diagram</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710655470072/ec1e92f9-cee6-400f-95bc-cbce0947b620.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>To Sum Up,</p>
<p>Domain layer serves as the heart of the application, encapsulating the core business logic, entities, and use cases.</p>
<p>Entities represent the fundamental concepts within the application's domain, while use cases define specific tasks or operations that the application can perform.</p>
<p>Repositories act as intermediaries between the domain layer and the data layer, abstracting away the complexities of data storage and retrieval.</p>
</blockquote>
<hr />
<h2 id="heading-data-layer">Data Layer</h2>
<p>The data layer in Clean Architecture handles the app's data. It connects the repository layer, which is the access point, to the real data sources like databases, files, and APIs.</p>
<p>It deals with getting, saving, and changing data, making sure the business logic (Domain Layer) and the user interface (UI) don't have to worry about these details.</p>
<p>Data layers consist of:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710656003472/328e55fe-1b54-499b-9198-82fd5fac897c.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-models">Models:</h4>
<ul>
<li><p>Models are like the blueprints for real-life stuff in our code. They're classes or structures that outline what attributes these things have and sometimes even how they behave.</p>
</li>
<li><p>It's pretty similar to Entities, but it comes with functions like <code>fromJson</code> and <code>toMap</code>. This helps the data layer turn the info/data from third-party APIs or databases into something we can work with.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsModel</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NewsEntity</span> </span>{
  <span class="hljs-keyword">const</span> NewsModel({
    <span class="hljs-keyword">required</span> <span class="hljs-built_in">String?</span> status,
    <span class="hljs-keyword">required</span> <span class="hljs-built_in">int?</span> totalResults,
    <span class="hljs-keyword">required</span> <span class="hljs-built_in">List</span>&lt;ArticleModel&gt;? articles,
  }) : <span class="hljs-keyword">super</span>(
          status: status,
          totalResults: totalResults,
          articles: articles,
        );

  <span class="hljs-keyword">factory</span> NewsModel.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) {
    <span class="hljs-keyword">return</span> NewsModel(
      status: json[<span class="hljs-string">'status'</span>],
      totalResults: json[<span class="hljs-string">'totalResults'</span>],
      articles: (json[<span class="hljs-string">'articles'</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">List</span>)
          .map((e) =&gt; ArticleModel.fromJson(e))
          .toList(),
    );
  }

  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-string">'status'</span>: status,
      <span class="hljs-string">'totalResults'</span>: totalResults,
      <span class="hljs-string">'articles'</span>:
          articles?.cast&lt;ArticleModel&gt;().map((e) =&gt; e.toJson()).toList(),
    };
  }
}
</code></pre>
<hr />
<h4 id="heading-repository">Repository</h4>
<ul>
<li><p>The Data layer's Repository is like the middleman between your app's core logic and where your data lives (like databases or APIs). It's the go-to place for getting and managing data.</p>
</li>
<li><p>It talks directly to either the Remote or Local data sources, deals with any errors that pop up when accessing data and makes sure these errors are handled in a consistent way that the rest of the app can work with.</p>
</li>
<li><p>It also takes on the job of converting data from the way it comes from the data source (like raw JSON) into the way your app needs it (like custom objects).</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRepositoryImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NewsRepository</span> </span>{
  <span class="hljs-keyword">final</span> NewsRemoteDataSource remoteDataSource;
  <span class="hljs-keyword">final</span> NewsLocalDataSource localDataSource;
  <span class="hljs-keyword">final</span> networkInfo = getIt.<span class="hljs-keyword">get</span>&lt;NetworkInfo&gt;();

  NewsRepositoryImpl(
      {<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.remoteDataSource, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.localDataSource});

  <span class="hljs-meta">@override</span>
  Future&lt;Either&lt;Failure, NewsModel&gt;&gt; getNews() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> networkInfo.isConnected!) { 
      <span class="hljs-comment">// Get data from remote if connected</span>
    } <span class="hljs-keyword">else</span> { 
      <span class="hljs-comment">// Get data from local databse if internet is disconnected</span>
    }
  }
}
</code></pre>
<hr />
<h4 id="heading-data-sources">Data Sources</h4>
<ul>
<li><p>This layer is all about talking with different kinds of data sources, whether it's grabbing stuff from APIs out there on the internet or digging into databases and files stored locally.</p>
</li>
<li><p>When we talk about data sources, we're looking at a whole bunch of options. You've got your traditional databases (think SQLite or MySQL), the cool NoSQL ones (like MongoDB), places to stash your files and settings, or even those network APIs for when you need to pull data from somewhere else.</p>
</li>
<li><p>Repositories act as the intermediary between the domain layer and data sources. They handle the specifics of interacting with each data source.</p>
</li>
<li><p>This decoupling allows you to switch between different data sources without affecting the core functionality of the application.</p>
</li>
</ul>
<p>Example</p>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRemoteDataSource</span> </span>{
  Future&lt;Response&gt; getNews();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsRemoteDataSourceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NewsRemoteDataSource</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;Response&gt; getNews() <span class="hljs-keyword">async</span> {
   <span class="hljs-comment">// Get data from APIs</span>
  }
}
</code></pre>
<p>Let's now update the diagram finally:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710777529693/1d06efa1-948b-4201-a2b0-6101f703c828.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>To Sum up,</p>
<p>The data layer acts as the <strong>silent orchestra</strong> behind your application's data management. It ensures smooth data access and manipulation, independent of how the domain logic operates.</p>
<p><strong>Repositories:</strong> The access point for the data layer. They provide interface for the domain layer to interact with data, hiding the complexities of specific data sources.</p>
<p><strong>Data Sources:</strong> The physical locations where your application's data resides, such as databases, files, or APIs.</p>
</blockquote>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><p>That was a lot to take in at once, I bet. But if you've clearly understood these concepts, you'll find it much easier when we start to apply Clean Architecture in our Flutter app in the next article.</p>
</li>
<li><p>If you have any question, I would be happy to answer all in the comments. So make sure you leave a comment.</p>
</li>
<li><p>We looked at the three main layers: <strong>Presentation</strong>, <strong>Domain</strong>, and <strong>Data</strong>,</p>
</li>
<li><p>Each layer has its own job, from handling user interactions to managing the core business logic and data.</p>
</li>
<li><p>We covered entities, use cases, and repositories, which are key parts of your app, making it flexible and efficient.</p>
</li>
</ul>
<hr />
<h2 id="heading-in-the-next-blog">In the next blog...</h2>
<ul>
<li><p>In our next blog, we're going to apply everything we've talked about so far.</p>
</li>
<li><p>We'll start building two real-world examples from scratch.</p>
</li>
<li><p>This hands-on approach will help you really understand entities, use cases, and repositories by seeing how they work in actual applications.</p>
</li>
<li><p>An upcoming blog will help you develop an app that's both flexible and easy to maintain. Stay tuned as I will show you how to turn these concepts into real software applications.</p>
</li>
</ul>
<hr />
<h2 id="heading-are-you-still-here">Are you still here?</h2>
<p>I hope you enjoyed reading the blog and found it useful. If you learned something, I would appreciate a comment and a thumbs up.</p>
<p>We will meet again in the next article until then...</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710778497475/1106a531-6d01-4fcf-9795-992aed2f4941.gif" alt class="image--center mx-auto" /></p>
<ul>
<li>Connect with me on <a target="_blank" href="https://twitter.com/dhruv_nakum"><strong>Twitter</strong></a>, <a target="_blank" href="https://www.linkedin.com/in/dhruv-nakum-4b1054176/"><strong>LinkedIn</strong></a>, and <a target="_blank" href="https://github.com/red-star25"><strong>Github</strong></a>.</li>
</ul>
]]></content:encoded></item></channel></rss>