<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Siddhesh Khandagale</title>
    <description>The latest articles on DEV Community by Siddhesh Khandagale (@siddheshk02).</description>
    <link>https://dev.to/siddheshk02</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg</url>
      <title>DEV Community: Siddhesh Khandagale</title>
      <link>https://dev.to/siddheshk02</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siddheshk02"/>
    <language>en</language>
    <item>
      <title>A must read if you are passionate about cryptography or security.</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Thu, 06 Feb 2025 12:15:16 +0000</pubDate>
      <link>https://dev.to/siddheshk02/a-must-read-if-you-are-passionate-about-cryptography-or-security-19ak</link>
      <guid>https://dev.to/siddheshk02/a-must-read-if-you-are-passionate-about-cryptography-or-security-19ak</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/siddheshk02" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg" alt="siddheshk02"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/siddheshk02/splitting-secrets-like-a-spy-shamirs-secret-sharing-in-go-53b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Splitting Secrets Like a Spy: Shamir’s Secret Sharing in Go&lt;/h2&gt;
      &lt;h3&gt;Siddhesh Khandagale ・ Feb 6&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cryptography&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#shamirsecretsharing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#security&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>go</category>
      <category>cryptography</category>
      <category>shamirsecretsharing</category>
      <category>security</category>
    </item>
    <item>
      <title>Splitting Secrets Like a Spy: Shamir’s Secret Sharing in Go</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Thu, 06 Feb 2025 12:12:40 +0000</pubDate>
      <link>https://dev.to/siddheshk02/splitting-secrets-like-a-spy-shamirs-secret-sharing-in-go-53b</link>
      <guid>https://dev.to/siddheshk02/splitting-secrets-like-a-spy-shamirs-secret-sharing-in-go-53b</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Ever watched a movie where a nuclear launch code is split among multiple people, ensuring no single person has full control? Well, that’s &lt;strong&gt;Shamir’s Secret Sharing (SSS)&lt;/strong&gt; in action! 🕵️‍♂️✨&lt;/p&gt;

&lt;p&gt;A while back, I built a &lt;strong&gt;CLI app&lt;/strong&gt; using Shamir’s Secret Sharing in Go, allowing secure file sharing. The flow was simple: upload a file, define the number of shares and threshold, and assign them to specific people through the app. To reconstruct the file, shareholders had to collect enough shares and input them into the CLI. If the threshold was met with correct shares, the encrypted file was recovered. Pretty cool, right? 🔥&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxxvhb17srby911a1ey5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxxvhb17srby911a1ey5.png" alt="Image description" width="415" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can read more about this CLI app here 👉 &lt;a href="https://ieeexplore.ieee.org/document/10346324" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s break down how this powerful cryptographic method works and how you can implement it in Go! 🚀&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Shamir’s Secret Sharing?
&lt;/h3&gt;

&lt;p&gt;Shamir’s Secret Sharing (SSS) is a &lt;strong&gt;cryptographic method&lt;/strong&gt; where a secret is split into multiple shares. Only a certain number of shares (threshold) are needed to reconstruct the original secret. Think of it like splitting a treasure map into different pieces — nobody can find the treasure unless they have enough parts! 🏴‍☠️&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You split your &lt;strong&gt;private key&lt;/strong&gt; into &lt;strong&gt;5 shares&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You set a threshold of 3 (minimum required to reconstruct it).&lt;/li&gt;
&lt;li&gt;Even if 2 shares are lost, the key is still recoverable!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementing Shamir’s Secret Sharing in Go
&lt;/h3&gt;

&lt;p&gt;We’ll use &lt;code&gt;github.com/hashicorp/vault/shamir&lt;/code&gt;, a robust Go package that makes splitting and combining secrets effortless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Installing the Package
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/hashicorp/vault/shamir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Splitting the Secret
&lt;/h3&gt;



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

import (
 "fmt"
 "github.com/hashicorp/vault/shamir"
)

func main() {
 secret := []byte("super-secret-key") // Your top-secret data
 nShares := 5  // Total shares to generate
 threshold := 3 // Minimum shares required to reconstruct

 shares, err := shamir.Split(secret, nShares, threshold)
 if err != nil {
  panic(err)
 }

 fmt.Println("Generated Shares:")
 for i, share := range shares {
  fmt.Printf("Share %d: %x\n", i+1, share)
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ How It Works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes a &lt;strong&gt;secret&lt;/strong&gt; (e.g., private key, password, etc.).&lt;/li&gt;
&lt;li&gt;Splits it into &lt;strong&gt;nShares&lt;/strong&gt; (total number of shares).&lt;/li&gt;
&lt;li&gt;Requires a &lt;strong&gt;threshold&lt;/strong&gt; (minimum shares needed to reconstruct the secret).&lt;/li&gt;
&lt;li&gt;Prints out each generated &lt;strong&gt;share&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Reconstructing the Secret
&lt;/h3&gt;



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

import (
 "fmt"
 "github.com/hashicorp/vault/shamir"
)

func main() {
 // Use any 3 shares from the previous output
 shares := [][]byte{
  {0x01, 0xA2, 0x45, 0x56, 0x78},
  {0x02, 0xB3, 0x67, 0x89, 0x90},
  {0x03, 0xC4, 0x89, 0xAB, 0xBC},
 }

 secret, err := shamir.Combine(shares)
 if err != nil {
  panic(err)
 }

 fmt.Println("Reconstructed Secret:", string(secret))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ How It Works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses at least &lt;strong&gt;3 shares&lt;/strong&gt; to reconstruct the original secret.&lt;/li&gt;
&lt;li&gt;If fewer than &lt;strong&gt;3 shares&lt;/strong&gt; are used, the reconstruction &lt;strong&gt;fails&lt;/strong&gt; (that’s the security!).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why is This Useful? 🤔
&lt;/h3&gt;

&lt;p&gt;🔹 &lt;strong&gt;Securely store private keys&lt;/strong&gt; — Avoid a single point of failure.&lt;br&gt;
🔹 &lt;strong&gt;Distribute credentials safely&lt;/strong&gt; — Team-based authentication.&lt;br&gt;
🔹 &lt;strong&gt;Decentralized access control&lt;/strong&gt; — Ensures secrets can’t be accessed by a single person.&lt;br&gt;
🔹 &lt;strong&gt;Disaster recovery&lt;/strong&gt; — Lost a part of your key? No problem!&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We just built a &lt;strong&gt;spy-level&lt;/strong&gt; secret-sharing system in Go! 🎩🚀 Whether you’re handling encryption keys, sensitive files, or secure authentication, &lt;strong&gt;Shamir’s Secret Sharing&lt;/strong&gt; is an incredible way to &lt;strong&gt;safeguard data&lt;/strong&gt; against loss or theft.&lt;/p&gt;

&lt;p&gt;Would you use this in real life? Or build something even crazier? Let me know! 🔥&lt;/p&gt;

</description>
      <category>go</category>
      <category>cryptography</category>
      <category>shamirsecretsharing</category>
      <category>security</category>
    </item>
    <item>
      <title>Building a Self-Destructing CLI Tool in Go 🚀💣</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Tue, 04 Feb 2025 06:37:37 +0000</pubDate>
      <link>https://dev.to/siddheshk02/building-a-self-destructing-cli-tool-in-go-2c0n</link>
      <guid>https://dev.to/siddheshk02/building-a-self-destructing-cli-tool-in-go-2c0n</guid>
      <description>&lt;p&gt;Ever wondered what it feels like to build a program that &lt;strong&gt;deletes itself&lt;/strong&gt; after execution? Sounds crazy, right? Well, today, we are going to do just that, build a &lt;strong&gt;Self-Destructing CLI Tool in Go!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a fun experiment, but it also introduces some cool &lt;strong&gt;file handling&lt;/strong&gt; and &lt;strong&gt;process management&lt;/strong&gt; techniques in Go. Let’s get started!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;br&gt;
The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Go program executes normally.&lt;/li&gt;
&lt;li&gt;Before exiting, it deletes its own binary file.&lt;/li&gt;
&lt;li&gt;Once destroyed, the program is &lt;strong&gt;gone forever&lt;/strong&gt; (unless you recompile it). 🤯&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Writing the Self-Destructing Go Code
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Initialize a Go Project&lt;/strong&gt;&lt;br&gt;
First, create a new project directory and initialize a Go module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir self_destruct &amp;amp;&amp;amp; cd self_destruct
go mod init self_destruct
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file named &lt;code&gt;self_destruct.go&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

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

import (
 "fmt"
 "os"
 "os/exec"
)

func main() {
 fmt.Println("💀 Running self-destructing program...")

 // Get the current executable path
 exePath, err := os.Executable()
 if err != nil {
  fmt.Println("Failed to get executable path:", err)
  return
 }

 // Print the file path before deletion
 fmt.Println("Deleting:", exePath)

 // Create a command to delete the file
 if runtime.GOOS == "windows" {
     cmd = exec.Command("cmd", "/C", "del", exePath)
 } else {
     cmd = exec.Command("sh", "-c", fmt.Sprintf("rm -f %s", exePath))
 }
 cmd.Start() // Start but don't wait to prevent blocking
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down what this code does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;os.Executable()&lt;/code&gt; returns the absolute path of the currently running executable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fmt.Println("Deleting:", exePath)&lt;/code&gt;: Prints the file path before deletion so the user can see what’s happening.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exec.Command("cmd", "/C", "del", exePath)&lt;/code&gt; creates a command to delete the executable file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.Start()&lt;/code&gt; runs the command asynchronously to ensure the program doesn't hang while deleting itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Running the Program
&lt;/h3&gt;

&lt;p&gt;Compile the Program : &lt;code&gt;go build .&lt;/code&gt;&lt;br&gt;
Run the Program : &lt;code&gt;./self_destruct&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The binary file deletes itself after execution! Try running it again you’ll see it’s gone.&lt;/p&gt;

&lt;p&gt;While this was a fun experiment, there are some &lt;strong&gt;real-world applications&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security &amp;amp; Privacy&lt;/strong&gt; — Temporary scripts that auto-delete after execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleanup Mechanisms&lt;/strong&gt; — Self-cleaning build artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-Time Setup Scripts&lt;/strong&gt; — Ensure scripts don’t run twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was a crazy but entertaining experiment with &lt;strong&gt;Go’s file handling and process execution&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Would you ever use this in real life? Or have any other wacky Go ideas? Let me know! 🚀🔥&lt;/p&gt;

</description>
      <category>go</category>
      <category>cli</category>
      <category>backend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A Guide on Building a Concurrent Key-Value store using Golang</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Sat, 01 Feb 2025 06:49:09 +0000</pubDate>
      <link>https://dev.to/siddheshk02/a-guide-on-building-a-concurrent-key-value-store-using-golang-3na8</link>
      <guid>https://dev.to/siddheshk02/a-guide-on-building-a-concurrent-key-value-store-using-golang-3na8</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/siddheshk02" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg" alt="siddheshk02"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/siddheshk02/how-to-build-a-concurrent-key-value-store-in-go-3pep" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to Build a Concurrent Key-Value Store in Go&lt;/h2&gt;
      &lt;h3&gt;Siddhesh Khandagale ・ Jan 31&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#database&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#keyvaluestore&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>go</category>
      <category>database</category>
      <category>keyvaluestore</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Build a Concurrent Key-Value Store in Go</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Fri, 31 Jan 2025 15:23:36 +0000</pubDate>
      <link>https://dev.to/siddheshk02/how-to-build-a-concurrent-key-value-store-in-go-3pep</link>
      <guid>https://dev.to/siddheshk02/how-to-build-a-concurrent-key-value-store-in-go-3pep</guid>
      <description>&lt;p&gt;Key-Value stores are one of the simplest yet most effective forms of data storage used in modern applications.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will walk through building &lt;strong&gt;NanoKV&lt;/strong&gt;, a minimalist in-memory key-value store written in &lt;strong&gt;Go&lt;/strong&gt;, using the &lt;strong&gt;Fiber web framework&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you’ll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How key-value stores work under the hood&lt;/li&gt;
&lt;li&gt;Implementing basic CRUD operations in Go&lt;/li&gt;
&lt;li&gt;Using concurrency and TTL (Time-To-Live) for ephemeral data storage&lt;/li&gt;
&lt;li&gt;Running the application in a Docker container&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before we dive in, ensure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; installed (&lt;a href="https://go.dev/doc/install" rel="noopener noreferrer"&gt;Download here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Basic understanding of Go programming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; installed (optional, for containerization)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Let’s start by setting up our project structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Initialize a Go Project
&lt;/h3&gt;

&lt;p&gt;First, create a new project directory and initialize a Go module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir NanoKV &amp;amp;&amp;amp; cd NanoKV
go mod init NanoKV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Install Dependencies
&lt;/h3&gt;

&lt;p&gt;We’ll use &lt;strong&gt;Fiber&lt;/strong&gt; for building the API. Install it using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/gofiber/fiber/v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Project Structure
&lt;/h3&gt;

&lt;p&gt;Your project should have the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NanoKV/
│── kvstore/
│   └── kvstore.go
│── main.go
│── go.mod
│── go.sum
│── Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing the Key-Value Store
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Defining the Store Structure
&lt;/h4&gt;

&lt;p&gt;Create a new file &lt;code&gt;kvstore/kvstore.go&lt;/code&gt; and define the data structure:&lt;br&gt;
&lt;/p&gt;

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

import (
    "sync"
    "time"
)

type Data struct {
    value      string
    expiration time.Time
}

type KeyValueStore struct {
    mu   sync.RWMutex
    data map[string]Data
}

func NewKeyValueStore() *KeyValueStore {
    return &amp;amp;KeyValueStore{
        data: make(map[string]Data),
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we use a &lt;strong&gt;map&lt;/strong&gt; to store the actual key-value pairs. A map in Go is a built-in data structure that allows us to associate keys with values efficiently. However, since our key-value store is meant to be accessed concurrently (multiple goroutines may try to read or write to it at the same time), we need a mechanism to ensure safe concurrent access.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;sync.RWMutex&lt;/strong&gt; comes in. It is a read-write mutual exclusion lock that allows multiple goroutines to read data simultaneously but ensures that only one goroutine can write at a time. This helps prevent race conditions and maintains data consistency.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sync.RWMutex&lt;/code&gt; has two primary operations:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RLock()&lt;/code&gt; and &lt;code&gt;RUnlock()&lt;/code&gt; are used for &lt;strong&gt;read operations&lt;/strong&gt;, allowing multiple readers to access the data simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Lock()&lt;/code&gt; and &lt;code&gt;Unlock()&lt;/code&gt; are used for &lt;strong&gt;write operations&lt;/strong&gt;, ensuring that only one goroutine can modify the data at any given time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By wrapping our key-value store operations (such as &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;Get&lt;/code&gt;, and &lt;code&gt;Delete&lt;/code&gt;) with these locks, we guarantee thread safety while maintaining high performance for concurrent reads.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Implementing CRUD Operations with TTL Support
&lt;/h4&gt;

&lt;p&gt;Next, we implement methods to set, get, and delete key-value pairs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func (kv *KeyValueStore) Set(key, val string, ttl time.Duration) {
    kv.mu.Lock()
    defer kv.mu.Unlock()

    kv.data[key] = Data{
        value:      val,
        expiration: time.Now().Add(ttl),
    }
}

func (kv *KeyValueStore) Get(key string) (string, bool) {
    kv.mu.Lock()
    defer kv.mu.Unlock()
    val, ok := kv.data[key]

    // Check for Item Expiry
    if val.expiration.IsZero() || time.Now().Before(val.expiration) {
        return val.value, ok
    }

    // Delete if Expired
    delete(kv.data, key)
    return "", false
}

func (kv *KeyValueStore) Delete(key string) bool {
    kv.mu.Lock()
    defer kv.mu.Unlock()

    _, ok := kv.data[key]
    if !ok {
        return false
    }
    delete(kv.data, key)
    return true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set Method&lt;/strong&gt;: Stores a key-value pair with an expiration time. If the TTL (time-to-live) is set, it calculates the expiration timestamp. The function locks the store before writing and unlocks after completion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get Method&lt;/strong&gt;: Retrieves a value from the store. If the key exists and has not expired, it returns the value. If expired, it removes the key and returns false.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete Method&lt;/strong&gt;: Removes a key-value pair from the store. If the key exists, it deletes it and returns &lt;code&gt;true&lt;/code&gt;; otherwise, it returns &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Handling&lt;/strong&gt;: A read-write mutex (&lt;code&gt;sync.RWMutex&lt;/code&gt;) ensures thread safety by preventing race conditions when multiple goroutines access the store.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exposing an HTTP API with Fiber
&lt;/h3&gt;

&lt;p&gt;To make our key-value store accessible via HTTP, we set up a simple REST API using &lt;strong&gt;Fiber&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Setting Up the HTTP Server
&lt;/h4&gt;

&lt;p&gt;Create a &lt;code&gt;main.go&lt;/code&gt; file and add the following:&lt;br&gt;
&lt;/p&gt;

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

import (
    "time"
    "NanoKV/kvstore"
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()
    kv := kvstore.NewKeyValueStore()

    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("This is a Simple Key-Value store like Redis in Go.")
    })

    app.Get("/get/:key", func(c *fiber.Ctx) error {
        key := c.Params("key")
        value, ok := kv.Get(key)
        if !ok {
            return c.SendString("The Key " + key + " doesn't exist")
        }
        return c.SendString("The Key " + key + " has Value " + value)
    })

    app.Post("/set/:key/:value", func(c *fiber.Ctx) error {
        key := c.Params("key")
        value := c.Params("value")
        kv.Set(key, value, 10*time.Minute)
        return c.SendString("Key " + key + " Value " + value)
    })

    app.Delete("/delete/:key", func(c *fiber.Ctx) error {
        key := c.Params("key")
        ok := kv.Delete(key)
        if !ok {
            return c.SendString("The Key " + key + " doesn't exist")
        }
        return c.SendString("Successfully Deleted!!")
    })

    app.Listen(":3000")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GET&lt;/strong&gt; &lt;code&gt;/get/:key&lt;/code&gt;: Fetches the value of a given key if it exists; otherwise, returns a message indicating the key does not exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;POST&lt;/strong&gt; &lt;code&gt;/set/:key/:value&lt;/code&gt;: Stores a key-value pair with a default TTL of 10 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DELETE&lt;/strong&gt; &lt;code&gt;/delete/:key&lt;/code&gt;: Deletes a key from the store if it exists.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Running the Server
&lt;/h4&gt;

&lt;p&gt;Run the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test it using &lt;strong&gt;curl&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST http://localhost:3000/set/foo/bar
curl -X GET http://localhost:3000/get/foo
curl -X DELETE http://localhost:3000/delete/foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Containerizing the Application with Docker
&lt;/h4&gt;

&lt;p&gt;We can containerize our Go application using the following &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang:alpine

WORKDIR /app

COPY go.mod ./
COPY go.sum ./
RUN go mod download

COPY . ./

RUN go build -o NanoKV .

EXPOSE 3000

CMD ["/app/NanoKV"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Building and Running the Docker Container
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t nanokv .
docker run -p 3000:3000 nanokv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can get the complete code &lt;a href="https://github.com/Siddheshk02/NanoKV" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We have successfully built a &lt;strong&gt;lightweight in-memory key-value store in Go&lt;/strong&gt;, complete with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Basic CRUD operations&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Concurrency handling&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- TTL-based expiration&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- An HTTP API using Fiber&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Containerization with Docker&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can further enhance this by adding features like &lt;strong&gt;persistent storage&lt;/strong&gt;, &lt;strong&gt;distributed setup&lt;/strong&gt;, or &lt;strong&gt;enhanced performance optimizations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s it for this Tutorial. If this blog was helpful to you do share it and to get more information about Golang concepts, projects, etc. and to stay updated on the Tutorials do follow Siddhesh on &lt;a href="https://twitter.com/siddhesh1102" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/Siddheshk02" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until then &lt;strong&gt;Keep Learning, Keep Building&lt;/strong&gt; 🚀🚀&lt;/p&gt;

</description>
      <category>go</category>
      <category>database</category>
      <category>keyvaluestore</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Here's the new Step-by-Step tutorial for building a URL Shortner from scratch using Go, Redis and Docker.</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Wed, 29 Jan 2025 16:20:23 +0000</pubDate>
      <link>https://dev.to/siddheshk02/heres-the-new-step-by-step-tutorial-for-building-a-url-shortner-from-scratch-using-go-redis-and-47ba</link>
      <guid>https://dev.to/siddheshk02/heres-the-new-step-by-step-tutorial-for-building-a-url-shortner-from-scratch-using-go-redis-and-47ba</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/siddheshk02" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg" alt="siddheshk02"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/siddheshk02/url-shortening-service-using-go-3652" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;URL Shortening Service using Go&lt;/h2&gt;
      &lt;h3&gt;Siddhesh Khandagale ・ Jan 29&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#backend&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>go</category>
      <category>api</category>
      <category>backend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>URL Shortening Service using Go</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Wed, 29 Jan 2025 16:15:58 +0000</pubDate>
      <link>https://dev.to/siddheshk02/url-shortening-service-using-go-3652</link>
      <guid>https://dev.to/siddheshk02/url-shortening-service-using-go-3652</guid>
      <description>&lt;p&gt;Ever wondered how services like Bitly turn long, ugly URLs into short, shareable links?&lt;/p&gt;

&lt;p&gt;In this tutorial, I’ll walk you through building a &lt;strong&gt;URL Shortener&lt;/strong&gt; from scratch using &lt;strong&gt;Go&lt;/strong&gt;, &lt;strong&gt;Redis&lt;/strong&gt; and &lt;strong&gt;Docker&lt;/strong&gt;. If you’re a budding developer, this project is a fantastic way to level up your skills and learn practical web development.&lt;/p&gt;

&lt;h4&gt;
  
  
  What You’ll Learn
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a Go project with modules.&lt;/li&gt;
&lt;li&gt;Building RESTful APIs in Go.&lt;/li&gt;
&lt;li&gt;Using Redis for quick key-value storage.&lt;/li&gt;
&lt;li&gt;Organizing Go code for readability and scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Prerequisites / Installation:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Docker Desktop ( Install Docker Desktop on your system)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize Your Project
&lt;/h3&gt;

&lt;p&gt;Start by creating a directory for your project and initializing a Go module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir url-shortener
cd url-shortener
go mod init github.com/&amp;lt;username&amp;gt;/url-shortener
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;go.mod&lt;/code&gt; file to manage dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Set Up the Project Structure
&lt;/h3&gt;

&lt;p&gt;To keep things clean and modular, create the following folder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;url-shortener/
├── handlers/         # API logic for handling requests
│   └── handlers.go
├── models/           # Data models
│   └── url.go
├── router/           # Routing setup
│   └── router.go
├── storage/          # Redis interactions
│   └── redis-store.go
├── main.go           # Application entry point
├── Dockerfile        # Docker configuration
├── docker-compose.yml
└── go.mod            # Go module file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;We’ll use the following Go packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;github.com/go-redis/redis/v8&lt;/code&gt; for Redis interactions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/gorilla/mux&lt;/code&gt; for routing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install them using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/go-redis/redis/v8
go get github.com/gorilla/mux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Define Data Models
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;models/url.go&lt;/code&gt; to define the data structures for request and response:&lt;br&gt;
&lt;/p&gt;

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

type ShortenRequest struct {
 URL string `json:"url"` // URL to be shortened
}

type ShortenResponse struct {
 ShortURL string `json:"short_url"` // Generated short URL
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ShortenRequest&lt;/code&gt; struct represents the input, and &lt;code&gt;ShortenResponse&lt;/code&gt; defines the output format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Configure Redis Storage
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;storage/redis-store.go&lt;/code&gt;, create a &lt;code&gt;RedisStore&lt;/code&gt; struct to handle Redis operations:&lt;br&gt;
&lt;/p&gt;

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

import (
 "context"
 "fmt"
 "hash/fnv"
 "net/url"
 "strings"

 "github.com/go-redis/redis/v8"
)

// Context for Redis operations
var ctx = context.Background()

type RedisStore struct {
 Client *redis.Client
 // client *redis.Client
}

// NewRedisStore initializes a new Redis client and returns a RedisStore
func NewRedisStore() *RedisStore {
 rdb := redis.NewClient(&amp;amp;redis.Options{
  Addr: "localhost:6379",
  DB:   0,
 })

 return &amp;amp;RedisStore{Client: rdb}
}

func NewTestRedisStore() *RedisStore {
 rdb := redis.NewClient(&amp;amp;redis.Options{
  Addr: "localhost:6379",
  DB:   1,
 })

 return &amp;amp;RedisStore{Client: rdb}
}

// SaveURL stores the original URL and its shortened version in Redis
func (s *RedisStore) SaveURL(originalURL string) (string, error) {
 // Check if the URL already exists
 shortURL, err := s.Client.Get(ctx, originalURL).Result()
 if err == redis.Nil {
  // URL not found, generate a new short URL
  shortURL = s.generateShortURL(originalURL)
  err = s.Client.Set(ctx, originalURL, shortURL, 0).Err()
  if err != nil {
   return "", err
  }

  // Store the original URL and the short URL in Redis
  err = s.Client.Set(ctx, shortURL, originalURL, 0).Err()
  if err != nil {
   return "", err
  }

  // Increment the domain count in Redis
  domain, err := s.getDomain(originalURL)
  if err != nil {
   return "", err
  }

  err = s.Client.Incr(ctx, fmt.Sprintf("domain:%s", domain)).Err()
  if err != nil {
   return "", err
  }

 } else if err != nil {
  return "", err
 }

 return shortURL, nil
}

// GetOriginalURL retrieves the original URL from Redis using the short URL
func (s *RedisStore) GetOriginalURL(shortURL string) (string, error) {
 originalURL, err := s.Client.Get(ctx, shortURL).Result()
 if err == redis.Nil {
  return "", fmt.Errorf("URL not found")
 } else if err != nil {
  return "", err
 }

 return originalURL, nil
}

// GetDomainCounts retrieves the counts of shortened URLs per domain from Redis
func (s *RedisStore) GetDomainCounts() (map[string]int, error) {
 keys, err := s.Client.Keys(ctx, "domain:*").Result()
 if err != nil {
  return nil, err
 }

 domainCounts := make(map[string]int)

 for _, key := range keys {
  count, err := s.Client.Get(ctx, key).Int()
  if err != nil {
   return nil, err
  }

  domain := strings.TrimPrefix(key, "domain:")
  domainCounts[domain] = count
 }

 return domainCounts, nil
}

// generateShortURL creates a shortened URL string using a hash function
func (s *RedisStore) generateShortURL(originalURL string) string {
 h := fnv.New32a()
 h.Write([]byte(originalURL))
 return fmt.Sprintf("%x", h.Sum32())
}

// getDomain extracts the domain name from a URL
func (s *RedisStore) getDomain(originalURL string) (string, error) {
 parsedURL, err := url.Parse(originalURL)
 if err != nil {
  return "", err
 }

 return strings.TrimPrefix(parsedURL.Host, "www."), nil
}

func (s *RedisStore) FlushTestDB() {
 s.Client.FlushDB(ctx)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SaveURL&lt;/code&gt;: checks if a URL exists and generates a short URL if it doesn’t.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetOriginalURL&lt;/code&gt;: Retrieves the original URL from the short URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetDomainCounts&lt;/code&gt;: Fetches statistics for the top domains.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;generateShortURL&lt;/code&gt;: hashes the original URL using FNV-32. (&lt;code&gt;fnv.New32a()&lt;/code&gt; generates a 32-bit hash for a given URL.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getDomain&lt;/code&gt;: Extracts the domain name from a URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why FNV-1a?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s a fast, non-cryptographic hash function.&lt;/li&gt;
&lt;li&gt;Generates a short, deterministic hash for a given input.&lt;/li&gt;
&lt;li&gt;Perfect for URL shortening since we don’t need cryptographic security.&lt;/li&gt;
&lt;li&gt;Reduces collisions compared to basic modulo-based hashing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 6: Build Handlers
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;handlers/handlers.go&lt;/code&gt; to implement API logic:&lt;br&gt;
&lt;/p&gt;

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

import (
 "encoding/json"
 "net/http"
 "sort"

 "github.com/Siddheshk02/url-shortener/models"
 "github.com/Siddheshk02/url-shortener/storage"
 "github.com/gorilla/mux"
)

// Initialize the store as a RedisStore
var store = storage.NewRedisStore()

func ShortenURL(w http.ResponseWriter, r *http.Request) {
 // Decode the request body into a ShortenRequest struct
 var req models.ShortenRequest
 if err := json.NewDecoder(r.Body).Decode(&amp;amp;req); err != nil {
  http.Error(w, err.Error(), http.StatusBadRequest)
  return
 }

 // Save the URL using the store
 shortURL, err := store.SaveURL(req.URL)
 if err != nil {
  http.Error(w, err.Error(), http.StatusInternalServerError)
 }

 // Respond with the shortened URL
 res := models.ShortenResponse{ShortURL: shortURL}
 json.NewEncoder(w).Encode(res)
}

func RedirectURL(w http.ResponseWriter, r *http.Request) {
 // Get the short URL from the request variables
 vars := mux.Vars(r)
 shortURL := vars["shortURL"]

 // Get the original URL from the store
 originalURL, err := store.GetOriginalURL(shortURL)
 if err != nil {
  http.Error(w, err.Error(), http.StatusNotFound)
  return
 }

 // Redirect to the original URL
 http.Redirect(w, r, originalURL, http.StatusMovedPermanently)
}

func GetTopDomains(w http.ResponseWriter, r *http.Request) {
 // Get the domain counts from the store
 domainCounts, err := store.GetDomainCounts()
 if err != nil {
  http.Error(w, err.Error(), http.StatusInternalServerError)
  return
 }

 // Sort the domains by count
 type kv struct {
  Key   string
  Value int
 }

 var sortedDomains []kv
 for k, v := range domainCounts {
  sortedDomains = append(sortedDomains, kv{k, v})
 }

 sort.Slice(sortedDomains, func(i, j int) bool {
  return sortedDomains[i].Value &amp;gt; sortedDomains[j].Value
 })

 // Prepare the top 3 domains to return
 topDomains := make(map[string]int)
 for i, domain := range sortedDomains {
  if i &amp;gt;= 3 {
   break
  }
  topDomains[domain.Key] = domain.Value
 }

 // Respond with the top 3 domains
 json.NewEncoder(w).Encode(topDomains)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ShortenURL&lt;/code&gt;: Handles URL shortening requests.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RedirectURL&lt;/code&gt;: Redirects users to the original URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetTopDomains&lt;/code&gt;: Returns the most frequently shortened domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 7: Set Up Routes
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;router/router.go&lt;/code&gt;, define all the API routes:&lt;br&gt;
&lt;/p&gt;

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

import (
 "github.com/Siddheshk02/url-shortener/handlers"
 "github.com/gorilla/mux"
)

func SetupRouter() *mux.Router {
 // Initialize a new router
 r := mux.NewRouter()

 // Define route for getting the top domains
 r.HandleFunc("/metrics", handlers.GetTopDomains).Methods("GET")

 // Define route for shortening URLs
 r.HandleFunc("/shorten", handlers.ShortenURL).Methods("POST")

 // Define route for redirecting to the original URL
 r.HandleFunc("/{shortURL}", handlers.RedirectURL).Methods("GET")

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/shorten&lt;/code&gt; (POST): Shortens a given URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/{shortURL}&lt;/code&gt; (GET): Redirects to the original URL using the short URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/metrics&lt;/code&gt; (GET): Returns the top 3 most-used domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 8: Main Application Entry Point
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;main.go&lt;/code&gt;, initialize the router and start the HTTP server:&lt;br&gt;
&lt;/p&gt;

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

import (
 "log"
 "net/http"

 "github.com/Siddheshk02/url-shortener/router"
 "github.com/gorilla/mux"
)

func main() {
 // Setup the router from the router package
 r := router.SetupRouter()

 // Log all registered routes
 r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
  path, err := route.GetPathTemplate()
  if err != nil {
   return err
  }
  log.Println("Registered route:", path)
  return nil
 })

 log.Println("Starting server on 8080")
 log.Fatal(http.ListenAndServe(":8080", r))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;router.SetupRouter&lt;/code&gt;: Initializes all routes.&lt;/li&gt;
&lt;li&gt;Route Logging: Lists all registered routes for debugging.&lt;/li&gt;
&lt;li&gt;HTTP Server: Runs the app on port 8080.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 9: Dockerize the Application
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;Dockerfile&lt;/code&gt; to containerize the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Start with the official Golang image
FROM golang:1.22-alpine

# Set the working directory inside the container
WORKDIR /app

# Copy the Go modules files first and download dependencies
COPY go.mod go.sum ./
RUN go mod download

# Copy the rest of the application code
COPY . .

# Build the application
RUN go build -o url-shortener

# Expose the port on which the app will run
EXPOSE 8080

# Command to run the executable
CMD ["./url-shortener"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Dockerfile&lt;/code&gt; builds the Go application into a Docker image and sets it up to run on port &lt;code&gt;8080&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 10: Create a docker-compose.yml File
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;docker-compose.yml&lt;/code&gt; to define both the app and the Redis service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'

services:
  url-shortener:
    image: siddheshk02/url-shortener:latest
    ports:
      - "8080:8080"
    depends_on:
      - redis
    environment:
      - REDIS_HOST=redis
    networks:
      - app-network

  redis:
    image: redis
    ports:
      - "6379:6379"
    networks:
      - app-network

networks:
  app-network:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;url-shortener&lt;/code&gt; Service: Runs the Go app and depends on Redis.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redis&lt;/code&gt; Service: Provides the Redis database for storage.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;network&lt;/code&gt;: Ensures communication between the two services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 11: Run the Application
&lt;/h3&gt;

&lt;p&gt;Build and run the application using Docker Compose:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

&lt;p&gt;The Go app runs on &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;br&gt;
Redis is available on port &lt;code&gt;6379&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 12: Test the API Endpoints
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;Postman&lt;/strong&gt;, &lt;strong&gt;cURL&lt;/strong&gt;, or a browser to test the service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shorten a URL:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST -H "Content-Type: application/json" \
-d '{"url": "https://www.example.com"}' \
http://localhost:8080/shorten
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "short_url": "5c285a56"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redirect a Shortened URL:&lt;/strong&gt; Visit &lt;a href="http://localhost:8080/5c285a56" rel="noopener noreferrer"&gt;http://localhost:8080/5c285a56&lt;/a&gt; in your browser.&lt;br&gt;
It redirects to &lt;a href="https://www.example.com" rel="noopener noreferrer"&gt;https://www.example.com&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Get Top Domains:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "example.com": 5,
    "github.com": 3,
    "google.com": 2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Congratulations! 🎉 You’ve built a fully functional &lt;strong&gt;URL Shortening Service&lt;/strong&gt; in &lt;strong&gt;Go&lt;/strong&gt;. This project covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;URL Shortening:&lt;/strong&gt; Generating short URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirection:&lt;/strong&gt; Navigating users from short to original URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain Tracking:&lt;/strong&gt; Analyzing the most-used domains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dockerization:&lt;/strong&gt; Deploying the app in a containerized environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can get the complete code repository &lt;a href="https://github.com/Siddheshk02/url-shortener" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Steps&lt;/strong&gt;&lt;br&gt;
Here are some ways to enhance the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Short URLs:&lt;/strong&gt; Allow users to create custom short links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics:&lt;/strong&gt; Track the number of visits per short URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiration:&lt;/strong&gt; Add expiration times for short URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it for this Tutorial. If this blog was helpful to you do share it with other and to get more information about Golang concepts, projects, etc. and to stay updated on the Tutorials do follow &lt;a href="https://twitter.com/siddhesh1102" rel="noopener noreferrer"&gt;Siddhesh on Twitter&lt;/a&gt; and &lt;a href="https://github.com/Siddheshk02" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until then &lt;strong&gt;Keep Learning&lt;/strong&gt;, &lt;strong&gt;Keep Building&lt;/strong&gt; 🚀🚀&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
      <category>backend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Here's the 2nd Tutorial for the Scalable Go API Series 🚀</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Wed, 22 Jan 2025 16:11:23 +0000</pubDate>
      <link>https://dev.to/siddheshk02/heres-the-2nd-tutorial-for-the-scalable-go-api-series-14hl</link>
      <guid>https://dev.to/siddheshk02/heres-the-2nd-tutorial-for-the-scalable-go-api-series-14hl</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/siddheshk02" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg" alt="siddheshk02"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/siddheshk02/taking-pagination-to-the-next-level-sorting-and-filtering-in-go-apis-497d" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Taking Pagination to the Next Level: Sorting and Filtering in Go APIs&lt;/h2&gt;
      &lt;h3&gt;Siddhesh Khandagale ・ Jan 22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#pagination&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>go</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Taking Pagination to the Next Level: Sorting and Filtering in Go APIs</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Wed, 22 Jan 2025 15:58:36 +0000</pubDate>
      <link>https://dev.to/siddheshk02/taking-pagination-to-the-next-level-sorting-and-filtering-in-go-apis-497d</link>
      <guid>https://dev.to/siddheshk02/taking-pagination-to-the-next-level-sorting-and-filtering-in-go-apis-497d</guid>
      <description>&lt;p&gt;In the last post, we tackled &lt;strong&gt;Pagination&lt;/strong&gt; breaking down large API responses into manageable chunks. But if you've ever wanted to let users control &lt;strong&gt;how data is sorted&lt;/strong&gt; or &lt;strong&gt;filter specific results&lt;/strong&gt;, then you're ready for the next step: &lt;strong&gt;sorting&lt;/strong&gt; and &lt;strong&gt;filtering&lt;/strong&gt;.&lt;br&gt;
Let's dive in and make our APIs even more powerful by adding these features.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you haven't gone through the previous tutorial, here's the &lt;a href="https://dev.to/siddheshk02/how-to-paginate-api-responses-in-go-4cga"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Why Sorting and Filtering Matter
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfplhhrmc6gxij5yu4ip.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfplhhrmc6gxij5yu4ip.jpg" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
Pagination alone isn't always enough. Imagine a user searching for the newest items or only those created in a specific timeframe. Sorting and filtering let users: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Sort:&lt;/strong&gt; Choose the order of results (e.g. newest to oldest)&lt;br&gt;
&lt;strong&gt;- Filter:&lt;/strong&gt; Narrow down results to what they need (e.g. items created today)&lt;/p&gt;

&lt;p&gt;By combining pagination with sorting and filtering, we create a more user-friendly API.&lt;/p&gt;
&lt;h3&gt;
  
  
  Extending Our Database Query
&lt;/h3&gt;

&lt;p&gt;We'll build on the items table from the previous blog. To recap, here's the scheme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE items (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Sorting
&lt;/h3&gt;

&lt;p&gt;Sorting is all about ordering the results. We'll allow users to sort by the &lt;code&gt;name&lt;/code&gt; or &lt;code&gt;created_at&lt;/code&gt; columns in ascending or descending order.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Accept Sort Parameters
&lt;/h4&gt;

&lt;p&gt;Users will pass two query parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sort&lt;/code&gt; : The column to sort by ( &lt;code&gt;name&lt;/code&gt; or &lt;code&gt;created_at&lt;/code&gt; ).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;order&lt;/code&gt; : The sort direction ( &lt;code&gt;asc&lt;/code&gt; or &lt;code&gt;desc&lt;/code&gt; ).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/items?page=1&amp;amp;limit=10&amp;amp;sort=created_at&amp;amp;order=desc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Adjust the SQL Query
&lt;/h4&gt;

&lt;p&gt;We'll dynamically modify the SQL query to include sorting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Extract sort and order query parameters
sort := r.URL.Query().Get("sort")
order := r.URL.Query().Get("order")

// Validate the sort column
validSortColumns := map[string]bool{"name": true, "created_at": true}
if !validSortColumns[sort] {
    sort = "created_at" // Default sort column
}

// Validate the sort order
if order != "asc" &amp;amp;&amp;amp; order != "desc" {
    order = "asc" // Default sort order
}

// Modify the SQL query
query := fmt.Sprintf("SELECT id, name, created_at FROM items ORDER BY %s %s LIMIT $1 OFFSET $2", sort, order)
rows, err := db.Query(query, limit, offset)
if err != nil {
    http.Error(w, "Failed to fetch items", http.StatusInternalServerError)
    return
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Filtering
&lt;/h3&gt;

&lt;p&gt;Filtering lets users refine their search. For example, we can filter items by a &lt;strong&gt;date range&lt;/strong&gt; or items containing a specific keyword in their name.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Accept Filter Parameters
&lt;/h3&gt;

&lt;p&gt;We'll support two filters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; : Search for items containing a specific substring.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;created_after&lt;/code&gt; : Fetch items created after a specific date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example URL :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/items?page=1&amp;amp;limit=10&amp;amp;name=Item&amp;amp;created_after=2025-01-10 20:38:57.832777
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Adjust the SQL Query
&lt;/h3&gt;

&lt;p&gt;We'll add WHERE conditions to handle these filters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Extract filter query parameters
nameFilter := r.URL.Query().Get("name")
createdAfter := r.URL.Query().Get("created_after")

// Build the WHERE clause dynamically
whereClauses := []string{}
args := []interface{}{}
argIndex := 1

if nameFilter != "" {
    whereClauses = append(whereClauses, "name ILIKE $1")
    args = append(args, "%"+nameFilter+"%")
    argIndex++
}

if createdAfter != "" {
    whereClauses = append(whereClauses, fmt.Sprintf("created_at &amp;gt; $%d", argIndex))
    args = append(args, createdAfter)
    argIndex++
}

args = append(args, limit, offset)

// Combine WHERE clauses
whereSQL := ""
if len(whereClauses) &amp;gt; 0 {
    whereSQL = "WHERE " + strings.Join(whereClauses, " AND ")
}

// Final query
query := fmt.Sprintf("SELECT id, name, created_at FROM items %s ORDER BY %s %s LIMIT $%d OFFSET $%d", whereSQL, sort, order, argIndex, argIndex+1)
rows, err := db.Query(query, args...)
if err != nil {
    http.Error(w, "Failed to fetch items", http.StatusInternalServerError)
    return
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing the Enhanced API
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sorting by name in ascending order:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "http://localhost:8080/items?page=1&amp;amp;limit=5&amp;amp;sort=name&amp;amp;order=asc"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Filtering items created after a specific date:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "http://localhost:8080/items?page=1&amp;amp;limit=5&amp;amp;created_after=2025-01-10 20:38:57.832777"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Combining filters and sorting:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "http://localhost:8080/items?page=1&amp;amp;limit=5&amp;amp;name=Item&amp;amp;sort=created_at&amp;amp;order=desc"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common Mistake to Avoid
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Not validating user input&lt;/strong&gt;: Allowing arbitrary columns or invalid sort orders can expose your database to SQL injection. Always validate inputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion / Next Steps
&lt;/h3&gt;

&lt;p&gt;You can find the complete code repository for this tutorial &lt;a href="https://github.com/Siddheshk02/pagination" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With pagination, sorting, and filtering in place, your API is now more user-friendly and flexible. For even more advanced functionality, consider adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cursor-based pagination&lt;/strong&gt; for large datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faceted filtering&lt;/strong&gt; for complex searches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for the next post where we’ll explore these advanced techniques!&lt;/p&gt;

&lt;p&gt;To get more information about Golang concepts, projects, etc. and to stay updated on the Tutorials do follow &lt;a href="https://twitter.com/siddhesh1102" rel="noopener noreferrer"&gt;Siddhesh on Twitter&lt;/a&gt; and &lt;a href="https://github.com/Siddheshk02" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until then &lt;strong&gt;Keep Learning&lt;/strong&gt;, &lt;strong&gt;Keep Building&lt;/strong&gt; 🚀🚀&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
      <category>pagination</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Pagination using Go</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Fri, 10 Jan 2025 15:49:06 +0000</pubDate>
      <link>https://dev.to/siddheshk02/pagination-using-go-4735</link>
      <guid>https://dev.to/siddheshk02/pagination-using-go-4735</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/siddheshk02" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg" alt="siddheshk02"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/siddheshk02/how-to-paginate-api-responses-in-go-4cga" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to Paginate API Responses in Go&lt;/h2&gt;
      &lt;h3&gt;Siddhesh Khandagale ・ Jan 10&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#pagination&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#backend&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>How to Paginate API Responses in Go</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Fri, 10 Jan 2025 15:46:49 +0000</pubDate>
      <link>https://dev.to/siddheshk02/how-to-paginate-api-responses-in-go-4cga</link>
      <guid>https://dev.to/siddheshk02/how-to-paginate-api-responses-in-go-4cga</guid>
      <description>&lt;h3&gt;
  
  
  What Is Pagination, and Why Do We Need It?
&lt;/h3&gt;

&lt;p&gt;Imagine your application has a database with thousands of records. Sending all these records to users in a single API response:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slows down your application.&lt;/li&gt;
&lt;li&gt;Consumes excessive bandwidth.&lt;/li&gt;
&lt;li&gt;Overwhelms users with too much data at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pagination&lt;/strong&gt; solves this problem by splitting the data into smaller pages. Users get only subset of the data at a time, making APIs faster and applications smoother.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40c84mfziw53m3r3gili.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40c84mfziw53m3r3gili.jpg" alt="Pagination" width="800" height="572"&gt;&lt;/a&gt;Consider a giant bookshelf with hundreds of books. Instead of searching through the entire shelf, wouldn’t it be easier if the shelf were divided into sections like "Page 1", "Page 2", and so on? That’s exactly what pagination does!&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Database
&lt;/h3&gt;

&lt;p&gt;To demonstrate pagination, we’ll use a simple &lt;code&gt;items&lt;/code&gt; table in a PostgreSQL database. Here's the schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE items (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now insert some dummy data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO items (name) 
VALUES 
('Item 1'), ('Item 2'), ('Item 3'), ..., ('Item 100');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting Up a Go API with Pagination
&lt;/h3&gt;

&lt;p&gt;Let’s create an API endpoint &lt;code&gt;/items&lt;/code&gt; that accepts two query parameters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;page&lt;/strong&gt;: The page number (default: 1).&lt;br&gt;
&lt;strong&gt;limit&lt;/strong&gt;: The number of records per page (default: 10).&lt;/p&gt;

&lt;p&gt;Here’s the full implementation:&lt;br&gt;
&lt;/p&gt;

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

import (
    "database/sql"
    "fmt"
    "log"
    "net/http"
    "strconv"

    _ "github.com/lib/pq"
)

func main() {
    // Connect to the database
    db, err := sql.Open("postgres", "user=youruser password=yourpass dbname=yourdb sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    http.HandleFunc("/items", func(w http.ResponseWriter, r *http.Request) {
        // Extract 'page' and 'limit' query parameters
        page, err := strconv.Atoi(r.URL.Query().Get("page"))
        if err != nil || page &amp;lt; 1 {
            page = 1 // Default to page 1
        }
        limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
        if err != nil || limit &amp;lt; 1 {
            limit = 10 // Default to 10 items per page
        }

        // Calculate the OFFSET
        offset := (page - 1) * limit

        // Query the database
        rows, err := db.Query("SELECT id, name, created_at FROM items LIMIT $1 OFFSET $2", limit, offset)
        if err != nil {
            http.Error(w, "Failed to fetch items", http.StatusInternalServerError)
            return
        }
        defer rows.Close()

        // Process the rows
        items := []map[string]interface{}{}
        for rows.Next() {
            var id int
            var name string
            var createdAt string
            if err := rows.Scan(&amp;amp;id, &amp;amp;name, &amp;amp;createdAt); err != nil {
                http.Error(w, "Failed to scan items", http.StatusInternalServerError)
                return
            }
            items = append(items, map[string]interface{}{
                "id":         id,
                "name":       name,
                "created_at": createdAt,
            })
        }

        // Respond with JSON
        w.Header().Set("Content-Type", "application/json")
        fmt.Fprintf(w, `{"page":%d,"limit":%d,"items":%v}`, page, limit, items)
    })

    log.Println("Server is running on http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding the Logic :
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pagination Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Page&lt;/strong&gt;: Determines which set of records to fetch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit&lt;/strong&gt;: Specifies the number of records per page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Offset Calculation&lt;/strong&gt;&lt;br&gt;
The offset determines how many records to skip:&lt;br&gt;
&lt;code&gt;offset = (page - 1) * limit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Page 1&lt;/strong&gt; with limit=5 → offset = 0 (skip 0 records).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page 2&lt;/strong&gt; with limit=5 → offset = 5 (skip the first 5 records).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SQL Query&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use &lt;strong&gt;LIMIT&lt;/strong&gt; and &lt;strong&gt;OFFSET&lt;/strong&gt; in SQL to fetch the desired records:&lt;br&gt;
&lt;code&gt;SELECT id, name, created_at FROM items ORDER BY id LIMIT 5 OFFSET 5;&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Testing Your API
&lt;/h3&gt;

&lt;p&gt;Test your API using tools like Postman, cURL, or directly in a browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch the first page with 10 items:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "http://localhost:8080/items?page=1&amp;amp;limit=10"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Fetch the second page with 20 items:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "http://localhost:8080/items?page=2&amp;amp;limit=20"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  API Response
&lt;/h3&gt;

&lt;p&gt;Here’s an example response for &lt;code&gt;/items?page=2&amp;amp;limit=2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "page": 2,
    "limit": 2,
    "items": [map[created_at: 2025-01-10T20: 38: 57.832777Z id: 3 name:Item 3
        ] map[created_at: 2025-01-10T20: 38: 57.832777Z id: 4 name:Item 4
        ]
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common Doubts and Pitfalls
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Why not fetch all records and slice them in Go?&lt;/strong&gt; &lt;br&gt;
Because it’s inefficient. Imagine loading a million records into memory—your API will slow down and possibly crash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What happens if the &lt;code&gt;page&lt;/code&gt; or &lt;code&gt;limit&lt;/code&gt; parameters are missing?&lt;/strong&gt;&lt;br&gt;
Always set defaults (e.g., &lt;code&gt;page=1&lt;/code&gt;, &lt;code&gt;limit=10&lt;/code&gt;) to ensure your API doesn’t break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Can we optimize this further?&lt;/strong&gt;&lt;br&gt;
Yes! Use indexes on frequently queried columns (like &lt;code&gt;id&lt;/code&gt; or &lt;code&gt;created_at&lt;/code&gt;) for faster lookups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;With just a few lines of code and smart database querying, you’ve turned an overwhelming API response into something lightweight and user-friendly.&lt;/p&gt;

&lt;p&gt;Want to take it up a notch? Try adding total pages, next/previous links, or even cursor-based pagination for large-scale applications.&lt;/p&gt;

&lt;p&gt;To get more information about Golang concepts, projects, etc. and to stay updated on the Tutorials do follow &lt;a href="https://twitter.com/siddhesh1102" rel="noopener noreferrer"&gt;Siddhesh on Twitter&lt;/a&gt; and &lt;a href="https://github.com/Siddheshk02" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until then &lt;strong&gt;Keep Learning&lt;/strong&gt;, &lt;strong&gt;Keep Building&lt;/strong&gt; 🚀🚀&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
      <category>pagination</category>
      <category>backend</category>
    </item>
    <item>
      <title>Discover 5 must-know Go libraries to enhance your backend development!</title>
      <dc:creator>Siddhesh Khandagale</dc:creator>
      <pubDate>Fri, 03 Jan 2025 13:13:34 +0000</pubDate>
      <link>https://dev.to/siddheshk02/-28pe</link>
      <guid>https://dev.to/siddheshk02/-28pe</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/siddheshk02" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F802866%2F222c8ef9-01bf-4e24-8841-ff580d4954af.jpeg" alt="siddheshk02"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/siddheshk02/top-5-go-libraries-every-backend-developer-should-know-1nhn" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Top 5 Go Libraries Every Backend Developer Should Know&lt;/h2&gt;
      &lt;h3&gt;Siddhesh Khandagale ・ Jan 3&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#backenddevelopment&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#learning&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>go</category>
      <category>backend</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
