<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Pradumna Saraf - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Pradumna Saraf - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 13 May 2026 20:28:04 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/Pradumnasaraf/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Flexible API with Feature Flags Using Open Source Tools ]]>
                </title>
                <description>
                    <![CDATA[ Feature flagging has changed the paradigm of how backend developers can test and modify the things they build. With feature flags, we can enable and disable a feature or change the functionality of something on the fly with a single click (no need to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-flexible-api-with-feature-flags-using-open-source-tools/</link>
                <guid isPermaLink="false">673d179a27c7af0d174dc2fc</guid>
                
                    <category>
                        <![CDATA[ Open Source ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redis ]]>
                    </category>
                
                    <category>
                        <![CDATA[   feature flags ]]>
                    </category>
                
                    <category>
                        <![CDATA[ backend developments ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Pradumna Saraf ]]>
                </dc:creator>
                <pubDate>Tue, 19 Nov 2024 22:56:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732044691446/abd5596c-3523-4278-957c-109388690bcc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Feature flagging has changed the paradigm of how backend developers can test and modify the things they build. With feature flags, we can enable and disable a feature or change the functionality of something on the fly with a single click (no need to redeploy).</p>
<p>In this tutorial, we will see how feature flags help us to enable and disable a feature/a part of code whenever we want from the UI, without the need to redeploy the whole code.</p>
<p>To understand things more deeply, we will build an app from scratch, look at feature flagging capabilities, and use a tool called Flagsmith to manage our created feature flags from a single dashboard.</p>
<h2 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-feature-flag">What is a Feature Flag?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-feature-flags-for-backend-development">Feature Flags for Backend Development</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-use-open-source-tools">Why Use Open Source Tools?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lets-code">Let’s Code!</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-initializing-the-tools">Initializing the tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-creating-endpoints-for-the-api">Creating endpoints for the API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-feature-flagging">How to Add Feature Flagging</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-the-feature-flag-code-logic">Understanding the Feature Flag code logic</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-feature-flags-in-the-flasgsmith-dashboard">How to Create Feature Flags in the Flasgsmith Dashboard</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-rate-limiting-feature-flag">Rate Limiting Feature Flag</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-beta-feature-flag">Beta Feature Flag</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-the-access-key">Getting the Access Key</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-running-the-api">Running the API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-updating-the-ratelimit-flag">Updating the rate_limit Flag</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-feature-flags-with-the-github-app">How to Integrate Feature Flags with the GitHub App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-testing-the-flagsmith-github-app">Testing the Flagsmith GitHub App</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p><a target="_blank" href="https://go.dev/">Golang</a> installed and a medium-level understanding of it.</p>
</li>
<li><p>A running <a target="_blank" href="https://redis.io">Redis</a> instance (Remote or local instance)</p>
</li>
<li><p><a target="_blank" href="https://www.flagsmith.com/">Flagsmith</a> Account (It’s Free. We will cover this later in the article.)</p>
</li>
</ul>
<h2 id="heading-what-is-a-feature-flag">What is a Feature Flag?</h2>
<p>Feature Flag is a technique in development that allows teams to turn features on or off without modifying the source code or redeploying.</p>
<p>To make it a bit simpler, think of them as functioning sort of like conditional statements (for example, if-else statements): based on when something’s true or false, it determines the code path that will be executed.</p>
<h2 id="heading-feature-flags-for-backend-development">Feature Flags for Backend Development</h2>
<p>You may have seen feature flags used in frontends and websites, but there is much more to them. You can use them on the server side to modify the functionality of an API, doing things like modifying/setting the rate limit, changing the API endpoint's functionality or completely turning it off. As backend developers, we can level up our testing with feature flags.</p>
<p>To demonstrate this, we will go through building a demo app. The demo app is curated to show feature flagging capabilities from modifying the functionality (rate limit) on the fly to adding a new endpoint to the API for beta testing or initial rolling purposes. We’ll use entirely open-source tools along the way!</p>
<h2 id="heading-why-use-open-source-tools">Why Use Open Source Tools?</h2>
<p>We will be using open source tools to build this app (Golang, <a target="_blank" href="https://redis.io/">Redis</a>, and <a target="_blank" href="https://www.flagsmith.com/?utm_source=thirdparty&amp;utm_medium=freecodecamp&amp;utm_campaign=pradumna">Flagsmith</a>). Open source brings more transparency and trust and encourages collaboration with the global community of backend developers.</p>
<p>By integrating open source tools, we get full visibility as we build and test. For example, we will integrate feature flags with GitHub, which lets us track the lifecycle of a feature by linking a Flagsmith feature flag with a GitHub Pull Request or Issue. This lets us stay updated with the changes to our features without having to manually track each modification. We can easily track the status of our features across different environments.</p>
<h2 id="heading-lets-code">Let’s Code!</h2>
<p>In this tutorial, you’ll see how the functionality of an app changes before and after testing with feature flagging mechanisms. The tools and frameworks we’ll use are Golang, Docker, Redis, Flagsmith, and GitHub. As discussed, all are open source and free to create an account to test.</p>
<p>To get started, open your favourite IDE, initialize a Golang project, and then copy the below code in the <code>main.go</code> file. Then run <code>go mod tidy</code> to install all the dependencies it needs.</p>
<p>Let’s understand what’s going on in the below code snippet:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"errors"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"strconv"</span>

    <span class="hljs-string">"github.com/gin-gonic/gin"</span>
    <span class="hljs-string">"github.com/go-redis/redis_rate/v10"</span>
    <span class="hljs-string">"github.com/joho/godotenv"</span>
    <span class="hljs-string">"github.com/redis/go-redis/v9"</span>
)

<span class="hljs-keyword">var</span> (
    redisClient *redis.Client
    limiter     *redis_rate.Limiter
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">initClients</span><span class="hljs-params">()</span></span> {
    redisClient = redis.NewClient(&amp;redis.Options{
        Addr: os.Getenv(<span class="hljs-string">"REDIS_URL"</span>),
    })
    limiter = redis_rate.NewLimiter(redisClient)
}

<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.Printf(<span class="hljs-string">"Loading environment variable from the host system"</span>)
    } <span class="hljs-keyword">else</span> {
        log.Printf(<span class="hljs-string">"Loading environment from .env file"</span>)
    }

    initClients()
    <span class="hljs-keyword">defer</span> redisClient.Close()

    r := gin.Default()
    r.GET(<span class="hljs-string">"/ping"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        err, remainingLimit := rateLimitCall(c.ClientIP())
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            c.JSON(
                http.StatusTooManyRequests,
                gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Rate Limit Hit"</span>})
        } <span class="hljs-keyword">else</span> {
            c.JSON(
                http.StatusOK,
                gin.H{<span class="hljs-string">"Your left over API request is"</span>: remainingLimit})
        }
    })
    r.GET(<span class="hljs-string">"/beta"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        c.JSON(
            http.StatusOK,
            gin.H{<span class="hljs-string">"message"</span>: <span class="hljs-string">"This is beta endpoint"</span>})
    })
    r.Run(<span class="hljs-string">":"</span> + os.Getenv(<span class="hljs-string">"PORT"</span>))
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">rateLimitCall</span><span class="hljs-params">(ClientIP <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(error, <span class="hljs-keyword">int</span>)</span></span> {
    ctx := context.Background()

    rateLimitString := os.Getenv(<span class="hljs-string">"RATE_LIMIT"</span>)
    RATE_LIMIT, _ := strconv.Atoi(rateLimitString)

    res, err := limiter.Allow(ctx, ClientIP, redis_rate.PerHour(RATE_LIMIT))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(err)
    }

    <span class="hljs-keyword">if</span> res.Remaining == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"You have hit the Rate Limit for the API. Try again later"</span>), <span class="hljs-number">0</span>
    }

    fmt.Println(<span class="hljs-string">"remaining request for"</span>, ClientIP, <span class="hljs-string">"is"</span>, res.Remaining)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, res.Remaining
}
</code></pre>
<h3 id="heading-initializing-the-tools">Initializing the Tools</h3>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">initClients</span><span class="hljs-params">()</span></span> {
    redisClient = redis.NewClient(&amp;redis.Options{
        Addr: os.Getenv(<span class="hljs-string">"REDIS_URL"</span>),
    })
    limiter = redis_rate.NewLimiter(redisClient)
}

<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.Printf(<span class="hljs-string">"Loading environment variable from the host system"</span>)
    } <span class="hljs-keyword">else</span> {
        log.Printf(<span class="hljs-string">"Loading environment from .env file"</span>)
    }

    initClients()
    <span class="hljs-keyword">defer</span> redisClient.Close()

    r := gin.Default()
    ...
    })
</code></pre>
<p>At the top, we declare variables to store Redis and Rate limiter clients to reuse and initialise them once. Then we initialise them in the <code>initClients()</code>.</p>
<p>In <code>main()</code>, first, we load the environment variables from the system or the .env file. Then we call <code>initClients()</code>. This will create clients and store them in the variables we created.</p>
<p>Next, we create a <strong>Gin</strong> router that handles all our incoming requests. These are the environment variables we need in our <code>.env</code> file. For this demo, we need a Redis instance running to store all the data for rate-limiting functionality. We can use Docker or any remote machine – just remember to update <code>REDIS_URL</code> accordingly. I am going to use Docker.</p>
<p>We could also go a mile ahead and get all the environment variables from the feature flags, but we won’t do this here.</p>
<pre><code class="lang-bash">REDIS_URL=localhost:6379
PORT=8080
RATE_LIMIT=10
</code></pre>
<h3 id="heading-creating-endpoints-for-the-api">Creating Endpoints for the API</h3>
<pre><code class="lang-go">r.GET(<span class="hljs-string">"/ping"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        err, remainingLimit := rateLimitCall(c.ClientIP())
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            c.JSON(
                http.StatusTooManyRequests,
                gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Rate Limit Hit"</span>})
        } <span class="hljs-keyword">else</span> {
            c.JSON(
                http.StatusOK,
                gin.H{<span class="hljs-string">"Your left over API request is"</span>: remainingLimit})
        }
    })
    r.GET(<span class="hljs-string">"/beta"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        c.JSON(
            http.StatusOK,
            gin.H{<span class="hljs-string">"message"</span>: <span class="hljs-string">"This is beta endpoint"</span>})
    })
    r.Run(<span class="hljs-string">":"</span> + os.Getenv(<span class="hljs-string">"PORT"</span>))
</code></pre>
<p>Then we create two <strong>GET</strong> endpoints, <code>/ping</code> and <code>/beta</code>. Every time someone hits the <code>/ping</code> endpoint we call the <code>rateLimitCall()</code> function. It checks and sets the rate limit of incoming requests from an <strong>IP address</strong>. All this is stored in the Redis instance we created.</p>
<p>So, now if the user has interacted with the <code>/ping</code> API endpoint for the first time, will create an entry with a limit of <strong>10 per hour</strong>. The limit number <strong>10</strong> comes from the <code>RATE_LIMIT</code> we set, and the hourly refresh form comes from the <code>redis_rate.PerHour(RATE_LIMIT)</code> function.</p>
<p>Next, we check if the user has a remaining limit. If yes, we will return a message with the number of requests they have remaining. Otherwise, if they hit the limit cap, we return a message letting them know this.</p>
<p>Apart from the <code>/ping</code> endpoint, we have another endpoint <code>/beta</code>. It returns a simple message, but later we’ll see how (using feature flags) we can completely turn on and off the functionality of this endpoint.</p>
<h3 id="heading-how-to-add-feature-flagging">How to Add Feature Flagging</h3>
<p>Now it’s time to add feature flagging capabilities to our app. We are going to use <a target="_blank" href="https://flagsmith.com/">Flagsmith</a>. Flagsmith is an open source software that lets us easily create and manage feature flags across web, mobile, and server-side applications.</p>
<p>Using Flagsmith, we can wrap features in a flag and then toggle them on or off for different environments, users, or user segments. And then you’ll be able to manage all of them from the Flagsmith dashboard without needing to redeploy.</p>
<p>So, let’s install the Flagsmith package by running the below command:</p>
<pre><code class="lang-bash">go get github.com/Flagsmith/flagsmith-go-client/v3
</code></pre>
<p>Then we import the package by giving it an alias <strong>flagsmith</strong>. Below is the updated functionality after we apply feature flagging to our existing code.</p>
<p>Let’s understand the changes we’ve made here (I’ll explain below the code snippet):</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

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

    flagsmith <span class="hljs-string">"github.com/Flagsmith/flagsmith-go-client/v3"</span>
    <span class="hljs-string">"github.com/gin-gonic/gin"</span>
    <span class="hljs-string">"github.com/go-redis/redis_rate/v10"</span>
    <span class="hljs-string">"github.com/joho/godotenv"</span>
    <span class="hljs-string">"github.com/redis/go-redis/v9"</span>
)

<span class="hljs-keyword">var</span> (
    redisClient     *redis.Client
    limiter         *redis_rate.Limiter
    flagsmithClient *flagsmith.Client
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">initClients</span><span class="hljs-params">()</span></span> {
    redisClient = redis.NewClient(&amp;redis.Options{
        Addr: os.Getenv(<span class="hljs-string">"REDIS_URL"</span>),
    })
    limiter = redis_rate.NewLimiter(redisClient)
    flagsmithClient = flagsmith.NewClient(os.Getenv(<span class="hljs-string">"FLAGSMITH_ENVIRONMENT_KEY"</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.Printf(<span class="hljs-string">"Loading environment variable from the host system"</span>)
    } <span class="hljs-keyword">else</span> {
        log.Printf(<span class="hljs-string">"Loading environment from .env file"</span>)
    }

    initClients()
    <span class="hljs-keyword">defer</span> redisClient.Close()

    r := gin.Default()
    r.GET(<span class="hljs-string">"/ping"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        err, remainingLimit := rateLimitCall(c.ClientIP())
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            c.JSON(
                http.StatusTooManyRequests,
                gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Rate Limit Hit"</span>})
        } <span class="hljs-keyword">else</span> {
            c.JSON(
                http.StatusOK,
                gin.H{<span class="hljs-string">"Your left over API request is"</span>: remainingLimit})
        }
    })
    r.GET(<span class="hljs-string">"/beta"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        flags := getFeatureFlags()
        isEnabled, _ := flags.IsFeatureEnabled(<span class="hljs-string">"beta"</span>)
        <span class="hljs-keyword">if</span> isEnabled {
            c.JSON(
                http.StatusOK,
                gin.H{<span class="hljs-string">"message"</span>: <span class="hljs-string">"This is beta endpoint"</span>})
        } <span class="hljs-keyword">else</span> {
            c.String(http.StatusNotFound, <span class="hljs-string">"404 page not found"</span>)
        }
    })

    r.Run(<span class="hljs-string">":"</span> + os.Getenv(<span class="hljs-string">"PORT"</span>))
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">rateLimitCall</span><span class="hljs-params">(ClientIP <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(error, <span class="hljs-keyword">int</span>)</span></span> {

    ctx := context.Background()

    flags := getFeatureFlags()
    rateLimitInterface, _ := flags.GetFeatureValue(<span class="hljs-string">"rate_limit"</span>)
    RATE_LIMIT := <span class="hljs-keyword">int</span>(rateLimitInterface.(<span class="hljs-keyword">float64</span>))
    fmt.Println(<span class="hljs-string">"Current Rate Limit is"</span>, RATE_LIMIT)

    res, err := limiter.Allow(ctx, ClientIP, redis_rate.PerHour(RATE_LIMIT))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(err)
    }

    <span class="hljs-keyword">if</span> res.Remaining == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"You have hit the Rate Limit for the API. Try again later"</span>), <span class="hljs-number">0</span>
    }

    fmt.Println(<span class="hljs-string">"remaining request for"</span>, ClientIP, <span class="hljs-string">"is"</span>, res.Remaining)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, res.Remaining
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getFeatureFlags</span><span class="hljs-params">()</span> <span class="hljs-title">flagsmith</span>.<span class="hljs-title">Flags</span></span> {
    ctx := context.Background()
    flags, _ := flagsmithClient.GetEnvironmentFlags(ctx)
    <span class="hljs-keyword">return</span> flags
}
</code></pre>
<h3 id="heading-understanding-the-feature-flag-code-logic">Understanding the Feature Flag Code Logic</h3>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getFeatureFlags</span><span class="hljs-params">()</span> <span class="hljs-title">flagsmith</span>.<span class="hljs-title">Flags</span></span> {
    ctx := context.Background()
    flags, _ := flagsmithClient.GetEnvironmentFlags(ctx)
    <span class="hljs-keyword">return</span> flags
}
</code></pre>
<p>First, let’s directly jump to the new <code>getFeatureFlags()</code> function we created at the bottom. This function will return all the flags we created on the Flagsmith dashboard, by calling the <code>GetEnvironmentFlags()</code> method on <code>flagsmithClient</code>.</p>
<p>We initiated the <code>flagsmithClient</code> inside the <code>initClients()</code> function. The Flagsmith Client needs the access key (the <code>NewClient()</code> function) that we can get from the Flagsmith dashboard. As we did for the Redis and Limter clients, we will store the client in a global variable for reusability. You’ll understand the dashboard, creating flags, and retrieving the key in later steps.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">rateLimitCall</span><span class="hljs-params">(ClientIP <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(error, <span class="hljs-keyword">int</span>)</span></span> {

    ctx := context.Background()

    flags := getFeatureFlags()
    rateLimitInterface, _ := flags.GetFeatureValue(<span class="hljs-string">"rate_limit"</span>)
    RATE_LIMIT := <span class="hljs-keyword">int</span>(rateLimitInterface.(<span class="hljs-keyword">float64</span>))
    fmt.Println(<span class="hljs-string">"Current Rate Limit is"</span>, RATE_LIMIT)

    res, err := limiter.Allow(ctx, ClientIP, redis_rate.PerHour(RATE_LIMIT))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(err)
    }

    <span class="hljs-keyword">if</span> res.Remaining == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"You have hit the Rate Limit for the API. Try again later"</span>), <span class="hljs-number">0</span>
    }

    fmt.Println(<span class="hljs-string">"remaining request for"</span>, ClientIP, <span class="hljs-string">"is"</span>, res.Remaining)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, res.Remaining
}
</code></pre>
<p>Now coming to the <code>rateLimitCall()</code> function, instead of getting <code>RATE_LIMIT</code> from the environment, we get the value from the <code>rate_limit</code> flag (that we will create later). We call <code>getFeatureFlags()</code> and get the flag <code>rate_limit</code> value out from all the flags.</p>
<p>By setting these as feature flags, we can dynamically change the limit anytime from the dashboard. We don’t need to change the code’s functionality or do it the traditional way by changing the <code>RATE_LIMIT</code> value and re-running the server so that it catches new updated values.</p>
<pre><code class="lang-go">    r.GET(<span class="hljs-string">"/beta"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        flags := getFeatureFlags()
        isEnabled, _ := flags.IsFeatureEnabled(<span class="hljs-string">"beta"</span>)
        <span class="hljs-keyword">if</span> isEnabled {
            c.JSON(
                http.StatusOK,
                gin.H{<span class="hljs-string">"message"</span>: <span class="hljs-string">"This is beta endpoint"</span>})
        } <span class="hljs-keyword">else</span> {
            c.String(http.StatusNotFound, <span class="hljs-string">"404 page not found"</span>)
        }
    })
</code></pre>
<p>Now coming to the <code>/beta</code> endpoint, based on whether the beta flag is enabled or disabled, this endpoint will serve the query. Otherwise, it will act as a non-reachable endpoint and return a 404 error message.</p>
<p>In our example, I have added a basic placeholder message to show how it will work, but this opens new possibilities in testing and initial releases (beta). If the API has a new endpoint, we can wrap the functionality in the feature flag and make it available and unavailable with a single click of a button. Also, we can do a lot more like scheduling and canary releases.</p>
<p>Also, our <code>.env</code> file will look like this. We have removed <code>RATE_LIMIT</code> and added <code>FLAGSMITH_ENVIRONMENT_KEY</code>.</p>
<pre><code class="lang-bash">REDIS_URL=localhost:6379
PORT=8080
FLAGSMITH_ENVIRONMENT_KEY=ser.ZRd***********469
</code></pre>
<h3 id="heading-how-to-create-feature-flags-in-the-flasgsmith-dashboard">How to Create Feature Flags in the Flasgsmith Dashboard</h3>
<p>Let’s head to the Flagsmith dashboard to create the flags we used above and get the access key. If you don’t have a Flagsmith account you can sign up for free <a target="_blank" href="https://app.flagsmith.com/signup">here</a>.</p>
<p>After you sign up you will be prompted to create an organisation and a project. Project separation is good, as it helps us isolate logic for different projects. Once you are done, you will see a dashboard, just like the screenshot below.</p>
<p>We have loads of functionalities from integrations to scheduling the flags to compare the changes. Apart from Go, Flagsmith provides many <a target="_blank" href="https://docs.flagsmith.com/clients/">SDKs</a>. You can click on where the language name is written and it will give you some boilerplate code for that language.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544211942/57f3651f-b62a-4b8f-beb7-4320ef0e0a8e.png" alt="Screenshot of a web interface labeled &quot;Features&quot; for managing feature flags and remote config. It includes examples of Go code for installing the SDK and initializing a project, with options to test API values. There are buttons and tabs for navigation and settings." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-rate-limiting-feature-flag">Rate Limiting Feature Flag</h3>
<p>Now, let's create our first feature flag for the rate limit. Click on the <strong>Create Feature</strong> button in the top right corner. A sidebar window will open up. Set the name, then to make the flag turn on the right way while creating, we can select <strong>Enabled by default.</strong></p>
<p>In the value section, we need to set the flag value. It can take formats like Txt, JSON, XML, and so on. As our feature value is simple text like 20, 30, and so on, we will choose Txt (the default one) and set a random limit – we’ll go with <strong>20</strong>.</p>
<p>You can also give tags and descriptions. Tags can be helpful when filtering out the Feature Flags. For example, we can create a tag <code>backend</code> to filter out all the feature flags related to Backend. The description is a concise explanation of what this particular future flag does when it is enabled (and will help with future understanding).</p>
<p>The screenshot below shows how it will look after filling in the details. Then, click on the <strong>Create Feature</strong> button to create the flag.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544238847/4e5cf3ab-1fb6-4783-afcc-39adcebae48e.png" alt="A screenshot of a web application interface showing the creation of a new feature. On the left, there is a menu with options like Features and SDK Keys. On the right, fields for adding a new feature are visible, including an ID/Name, a toggle for enabling by default, a value set to 20, and options for tags and descriptions. There is a note indicating feature creation for all environments, with a &quot;Create Feature&quot; button at the bottom." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-beta-feature-flag">Beta Feature Flag</h3>
<p>Let’s now create a second, <code>beta</code> feature flag. It will be the same process as the first one, but in this one, we don’t need to set any flag value and leave that column empty. Once we create both flags, our dashboard will look like this. It shows the flag name, value, current state (view), and so on.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544256561/3735429f-8dd0-4f0f-a01e-b4a4a7b5aa75.png" alt="A software interface showcasing a &quot;Features&quot; section with toggles for &quot;beta&quot; and &quot;rate_limit&quot; features. The page includes navigation options on the left and buttons for creating features and running tests." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-getting-the-access-key">Getting the Access Key</h3>
<p>To get the Access Key, click on the <strong>SDK Keys</strong> from the sidebar, and click the <strong>Create Server-side Environment Key</strong> button to generate a key. As our app is server-side, it’s good to use that one only. Then copy and paste that key into the value placed in <code>.env</code> for the <code>FLAGSMITH_ENVIRONMENT_KEY</code> key.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544280780/fc37cb29-3069-4e2f-b35b-eea7632c47cd.png" alt="Screenshot of a software interface showing &quot;Client-side Environment Key&quot; and &quot;Server-side Environment Keys&quot; sections. A button labeled &quot;Create Server-side Environment Key&quot; is displayed prominently. The sidebar menu includes options like &quot;SDK Keys&quot; and &quot;Environment Settings.&quot;" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-running-the-api">Running the API</h3>
<p>Now everything is set, so let’s head over back to IDE and run the server by executing the <code>go run main.go</code> command in the terminal. We will see this message In the terminal. In case you encounter any errors, just check that the packages are correctly installed, the variables are correctly set, and the app accesses the Redis instance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544780659/95fbbb17-43c3-4cd1-b84f-020c08ec38d3.png" alt="Screenshot of a VS Code window showing a Go project with the file &quot;main.go&quot; open. The code includes functions for rate limiting API calls and retrieving feature flags. The terminal at the bottom displays the output of running the application, with warnings and status messages related to a web server." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now if we visit <a target="_blank" href="http://localhost:8080/ping"><strong>localhost:8080/ping</strong></a>, we will get a message <code>{"Your left over API request is":19}</code>. The limit was 20, we did one request now, and the remaining is 19.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544374092/bc97064c-285e-44fa-990d-51a52a671d26.png" alt="A browser window displaying a webpage at &quot;localhost:8080/ping&quot; showing the JSON message: {&quot;Your left over API request is&quot;: 19}." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-updating-the-ratelimit-flag">Updating the <code>rate_limit</code> Flag</h3>
<p>Let’s update the <code>rate_limit</code> flag value to 10 and see what happens. To do so, again visit the Flagsmith dashboard and click on the flag name. A side menu bar will open. Update the value to 10, and click on the <strong>Update Feature Value</strong> button.</p>
<p>We can also schedule the update. For example, this can be useful when we expect a spike in traffic at a certain timeframe and reduce the limit per user to reduce server load.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730545050685/f253ea86-de3d-4a6a-b5fd-35f489da86cf.png" alt="Screenshot of a software dashboard showing a feature management interface. The &quot;rate_limit&quot; feature is enabled with a value of 10. Options include editing value, segment overrides, and scheduling updates." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>If you now visit <a target="_blank" href="http://localhost:8080/ping"><strong>localhost:8080/ping</strong></a>, you will get a message <code>{"Your left over API request is":8}</code> – because the total limit is 10 and we have already requested two times.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544415108/97e6fd9c-b5a1-4143-877a-6724cf871a6b.png" alt="Browser window displaying a JSON response with the text: &quot;Your left over API request is: 8&quot;." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Let's now test the <code>/beta</code> endpoint. Visit <a target="_blank" href="http://localhost:8080/beta">localhost:8080/beta</a>, and we will see a message <code>{"message":"This is beta endpoint"}</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544479869/623d8b72-3648-46ae-b79f-409da44c1d38.png" alt="Screenshot of a web browser displaying JSON data at the URL &quot;localhost:8080/beta&quot; with the message: &quot;This is beta endpoint&quot;." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now go back to the Flagsmith dashboard and toggle the switch to disable this flag. Now visit the the URL. You will get a 404 message like this endpoint never existed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544488522/518c58b2-f767-4396-9020-99e8cd01586a.png" alt="Screenshot of a browser window displaying a &quot;404 page not found&quot; error message." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now that we’ve set up the functionality and demoed the feature flagging capabilities, let’s see how we can integrate the Flasgsmith GitHub App.</p>
<h3 id="heading-how-to-integrate-feature-flags-with-the-github-app">How to Integrate Feature Flags with the GitHub App</h3>
<p>First, make sure you have pushed your app to GitHub. After that, install the GitHub Flasgsmith App on your repo from the <a target="_blank" href="https://github.com/apps/flagsmith">GitHub Marketplace</a>.</p>
<p>By integrating GitHub and Falagsmith, we can view updates on your feature flags/features as comments in GitHub Issues and Pull Requests. This allows us to easily track features, from creating an issue to merging a PR and deploying the changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544845464/dcce9af3-a34f-420a-b9c4-2968d47fda70.png" alt="Screenshot of the Flagsmith GitHub app integration page, detailing its features and benefits, with an option to install the app." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Then select your organisation and the repositories where you want to install the app. You can install it on all of your repos or select a particular one.</p>
<p>As you install it, you will be auto-redirected to the Flagmsith dashboard to configure and complete the integration. Most of the data will be pre-populated, so you just need to select and add a project, and then save the configuration.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730544640407/8ac36f96-d61b-47f7-ad3a-f914f0f01824.png" alt="Screenshot of a webpage for configuring GitHub integration with Flagsmith. It includes fields for selecting the organization, project, and repository, with options set for &quot;Pradumna,&quot; &quot;go-api,&quot; and &quot;go-redis-flagsmith.&quot; There is an &quot;Add Project&quot; button and a &quot;Save Configuration&quot; button at the bottom." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Once you hit the Save <strong>Configuration Button</strong>, it will redirect you back to the main Flagsmith dashboard where we were previously working.</p>
<p>Now let’s link one of the existing flags with the GitHub issue/pull request (raise a dummy PR/issue to test it), or you can create a new flag to test. Let’s proceed with the beta flag which we already created for the <code>beta</code> endpoint.</p>
<p>To link the flag with an existing issue or a pull request, click on the flag name, and a side menu will pop up from the right. Then, choose the 'Link' tab. Then select the Pull Request option, and choose the Pull Request you want to link. All of your Issues and Pull Requests linked to this flag are visible below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730546404697/0fb1c515-ab42-494d-ac84-87e076d30607.png" alt="A screenshot of a development environment interface showing the &quot;Features&quot; section, with a sidebar menu on the left. The &quot;Edit Feature: beta&quot; panel is open on the right, displaying options to link an issue or pull request and a listed pull request titled &quot;feat: Update the beta endpoint feature (#2)&quot; with its status marked as open." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>To verify that the flag is successfully linked, click the hyperlink with the arrow icon below the <strong>Name</strong> column heading. It will navigate you to that particular Issue/Pull Request on GitHub. You can see that the Flagsmith GitHub App has commented below with all the details, such as environment, enabled value, and so on.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730545132237/4601a08e-62d9-4ebc-890e-89430bf6624e.png" alt="GitHub pull request page showing a request titled &quot;feat: Update the beta endpoint feature #2&quot; to merge a commit from the &quot;beta&quot; branch into &quot;main&quot;. It includes a user comment about the update and a Flagsmith bot comment showing feature status for production and development environments. The pull request is open, with no reviews yet." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-testing-the-flagsmith-github-app">Testing the Flagsmith GitHub App</h3>
<p>After this, when you make any changes to the flag settings, such as turning on/off the flag or changing the value, the bot will comment with all the updated details.</p>
<p>Let’s test by turning the flag off. As soon as you turn off the flash from the Dashboard, the bot should comment that the flag has now been disabled:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730545146615/b76f2f21-369a-4617-b55b-abc3201a1c52.png" alt="Image showing a GitHub pull request interface. The pull request is titled &quot;feat: Update the beta endpoint feature #2&quot; and shows an update from the flagsmith bot indicating that the &quot;beta&quot; feature for the &quot;Development&quot; environment is currently disabled." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>That’s it. That is how it’s simple to integrate Flagsmith with GitHub.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>To sum it up, you now know how you can leverage feature flags as a backend developer to change the functionality of your app on the fly.</p>
<p>To take things to the next level, we integrated our demo app with the Flagsmith GitHub app so it could stay updated with the changes to our feature flags’ status on Pull Requests/Issues without having to manually update them.</p>
<p>Check out the Flagsmith <a target="_blank" href="https://github.com/Flagsmith/flagsmith">repo here</a> and don't forget to give each of these projects a star to show your support. You can also join their amazing <a target="_blank" href="https://discord.com/invite/hFhxNtXzgm">community</a> to get technical support.</p>
<p>You can connect with me - Pradumna Saraf, on socials <a target="_blank" href="https://links.pradumnasaraf.dev/">here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
