<?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[ Abhinav Pandey - 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[ Abhinav Pandey - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 28 May 2026 04:41:22 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/abh1navv/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Develop a CRUD App with Spring Boot, Neon Postgres, and Azure App Service ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we'll explore how to develop a CRUD (Create, Read, Update, Delete) application using Spring Boot and Neon Postgres. We'll also deploy the application on Azure App Service and make it production-ready by setting up features like autos... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-crud-app-spring-boot-neon-postgres/</link>
                <guid isPermaLink="false">66c3762340438b5931fe0a0b</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhinav Pandey ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jul 2024 19:14:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/neon-banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we'll explore how to develop a CRUD (Create, Read, Update, Delete) application using Spring Boot and <a target="_blank" href="https://neon.tech/">Neon Postgres</a>.</p>
<p>We'll also deploy the application on <a target="_blank" href="https://azure.microsoft.com/en-us/products/app-service">Azure App Service</a> and make it production-ready by setting up features like autoscaling and multiple environments.</p>
<p>You'll learn how Neon Postgres can make your development and deployment processes easier along the way.</p>
<h2 id="heading-heres-what-well-cover">Here's what we'll cover:</h2>
<ul>
<li>Setting up a Neon Postgres database and exploring its features</li>
<li>Building a CRUD application using Spring Boot and deploying the application on Azure App Service</li>
<li>Why Neon is a good fit for infrastructure that auto-scales</li>
<li>Database branching in Neon Postgres and how it can ease the development workflow</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Working knowledge of Java, Maven, and Spring Boot</li>
<li>Basics of SQL databases</li>
<li>Understanding of serverless and cloud services</li>
<li>Familiarity with testing and deployment processes</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-neon-postgres">What is Neon Postgres?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-database">How to Set Up the Database</a><ul>
<li><a class="post-section-overview" href="#heading-create-the-database">Create the Database</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-spring-boot-crud-app">How to Build the Spring Boot CRUD App</a><ul>
<li><a class="post-section-overview" href="#heading-create-an-entity-class">Create an Entity Class</a></li>
<li><a class="post-section-overview" href="#heading-create-a-repository">Create a Repository</a></li>
<li><a class="post-section-overview" href="#heading-create-a-rest-controller">Create a REST Controller</a></li>
<li><a class="post-section-overview" href="#heading-configure-the-database">Configure the Database</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-deploy-on-azure-app-service">How to Deploy on Azure App Service</a><ul>
<li><a class="post-section-overview" href="#heading-create-a-new-web-app">Create a New Web App</a></li>
<li><a class="post-section-overview" href="#heading-deploy-the-application">Deploy the Application</a></li>
<li><a class="post-section-overview" href="#heading-access-the-application">Access the Application</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-autoscaling">How to Set Up Autoscaling</a><ul>
<li><a class="post-section-overview" href="#heading-autoscaling-in-azure">Autoscaling in Azure</a></li>
<li><a class="post-section-overview" href="#heading-autoscaling-in-neon">Autoscaling in Neon</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-configure-database-branches-in-neon">How to Configure Database Branches in Neon</a></li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
</ul>
<h2 id="heading-what-is-neon-postgres">What is Neon Postgres?</h2>
<p>Neon is a fully managed serverless Postgres database platform. It offers features such as high availability, automatic backups, and scaling options to handle varying traffic levels.</p>
<p>Neon is designed to be cost-efficient and developer-friendly, and it focuses on providing a seamless experience for developers.</p>
<p>In addition to the standard Postgres features, it provides capabilities like database branching, allowing you to create Git-like branches of the database for different purposes.</p>
<h2 id="heading-how-to-set-up-the-database">How to Set Up the Database</h2>
<p>To begin with, let's explore how you can set up a Neon database for your application.</p>
<p>Firstly, you'll need to <a target="_blank" href="https://console.neon.tech/signup">create an account</a> on the Neon website. It doesn't require a credit card to sign up, and you're automatically set up with the free tier to get started.</p>
<p>Here's a <a target="_blank" href="https://neon.tech/pricing">pricing and features comparison</a> of Neon plans:</p>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finxumg46sf92ffre6l2q.png" alt="A screenshot of pricing plans in Neon listing down free and paid features" width="600" height="400" loading="lazy">
<em>Neon pricing plans</em></p>
<p>In the free tier, we get 0.5 GB of storage with basic computing which is enough for playing around with the database and building small applications.</p>
<h3 id="heading-create-the-database">Create the Database</h3>
<p>Once you've signed up, you can access the dashboard and create a new project.</p>
<p>Star by filling in the project name, region, and Postgres version options. In addition to this, we can choose two additional options:</p>
<ul>
<li><strong>compute size</strong> – You can choose a min and max compute size for the database. This is useful for autoscaling the database based on the load.</li>
<li><strong>suspend time</strong> – You can set a time after which the database will be suspended if not being used. This is useful for saving costs when the database is not being used.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggwuvqtb8ydl3mxd1dak.png" alt="Form with specifications required when creating a database" width="600" height="400" loading="lazy">
<em>Creating a database project in Neon</em></p>
<p>Once you submit the form, Neon will create the database and provide the connection details.</p>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2x5d81euphg2owgxhd.png" alt="Neon Dashboard showing the project is ready. Also shows connection details." width="600" height="400" loading="lazy">
<em>Neon Dashboard</em></p>
<p>As you can see, the database was set up in 3.3 seconds (compared to hours of installing and setting up your own infrastructure). You can choose multiple ways to connect to the database. For this tutorial, select Java as your programming language and get the JDBC connection string.</p>
<h2 id="heading-how-to-build-the-spring-boot-crud-app">How to Build the Spring Boot CRUD App</h2>
<p>Next, let's set up our CRUD application. We'll use Spring Boot, as it provides easy bootstrapping and configuration for building web applications.</p>
<p>We can use the <a target="_blank" href="https://start.spring.io/">Spring Initializr</a> to generate a new Spring Boot project with the necessary dependencies:</p>
<ul>
<li>Spring Web – for building web applications</li>
<li>Spring Data JPA – for working with databases using JPA</li>
<li>PostGres Driver – for connecting to the Postgres database</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffifv17tc5d3swothe3zf.png" alt="Spring Initializer website form to select spring boot project specifications and dependencies" width="600" height="400" loading="lazy">
<em>Creating a Spring Boot project using Spring Initializer</em></p>
<p>You can generate, download, and import the project into your favorite IDE.</p>
<h3 id="heading-create-an-entity-class">Create an Entity Class</h3>
<p>Let's create an entity class to represent the data in the application. First, create a <code>User</code> class:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Entity(name = "users")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@GeneratedValue(strategy = GenerationType.IDENTITY)</span>
    <span class="hljs-keyword">private</span> Long id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String email;

    <span class="hljs-comment">// Constructors, Getters and Setters</span>
}
</code></pre>
<p>The entity name <code>users</code> is the name of the table you want to use in your database.</p>
<h3 id="heading-create-a-repository">Create a Repository</h3>
<p>Next, create a repository interface to interact with the database. You'll extend the <code>JpaRepository</code> interface provided by Spring Data JPA:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Repository</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">Long</span>&gt; </span>{
}
</code></pre>
<p>You need to annotate the interface with <code>@Repository</code> to mark it as a Spring bean. The <code>JpaRepository</code> interface provides methods for CRUD operations like <code>save</code>, <code>findAll</code>, <code>findById</code>, <code>delete</code>, and so on, so you don't need to write the queries manually.</p>
<p>You'll provide your entity class <code>User</code> and the type of the primary key <code>Long</code> as type arguments to the <code>JpaRepository</code> interface.</p>
<h3 id="heading-create-a-rest-controller">Create a REST Controller</h3>
<p>Finally, create a REST controller to handle the CRUD operations. You'll inject the <code>UserRepository</code> into the controller and implement the necessary endpoints:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/users")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserController</span><span class="hljs-params">(UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-meta">@GetMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title">getUsers</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findAll();
    }

    <span class="hljs-meta">@PostMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">createUser</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> User user)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.save(user);
    }

    <span class="hljs-meta">@PutMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">updateUser</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id, <span class="hljs-meta">@RequestBody</span> User user)</span> </span>{
        user.setId(id);
        <span class="hljs-keyword">return</span> userRepository.save(user);
    }

    <span class="hljs-meta">@DeleteMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteUser</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id)</span> </span>{
        userRepository.deleteById(id);
    }
}
</code></pre>
<p>Here are a few things to note:</p>
<ul>
<li>You're using the <code>@RestController</code> annotation to mark the class as a controller that handles REST requests.</li>
<li>The <code>@RequestMapping</code> annotation specifies the base URL for the endpoints.</li>
<li>You're injecting the <code>UserRepository</code> into the controller using constructor injection.</li>
<li>Finally, you're implementing your API endpoints for CRUD operations using the <code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code>, and <code>@DeleteMapping</code> annotations.</li>
</ul>
<h3 id="heading-configure-the-database">Configure the Database</h3>
<p>To connect your Spring Boot application to the Neon Postgres database, you need to configure the database URL, username, and password in the <code>application.properties</code> file:</p>
<pre><code>spring.datasource.url=jdbc:postgresql:<span class="hljs-comment">//&lt;db-url&gt;/&lt;db-name&gt;?sslmode=require</span>
spring.datasource.username=&lt;username&gt;
spring.datasource.password=&lt;password&gt;
spring.jpa.hibernate.ddl-auto=update
</code></pre><p>Here, you configured the database URL, username, and password provided by Neon when you created the database. The <code>spring.jpa.hibernate.ddl-auto=update</code> property tells Spring Boot to automatically create the necessary tables or columns based on the entity classes when the application starts.</p>
<h2 id="heading-how-to-deploy-on-azure-app-service">How to Deploy on Azure App Service</h2>
<p>Now that your Spring Boot application is ready, it's time to deploy it on Azure App Service.</p>
<h3 id="heading-create-a-new-web-app">Create a New Web App</h3>
<p>To deploy your Spring Boot application on Azure App Service, you'll first create a new <code>Web App</code>. You can do this through the Azure portal by following these steps:</p>
<ul>
<li>Log in to the <a target="_blank" href="https://portal.azure.com/">Azure portal</a>.</li>
<li>Click on the <code>Create a resource</code> button.</li>
<li>Search for <code>Web App</code> and select the <code>Create</code> option.</li>
<li>Fill in the necessary details like resource group, app name, runtime stack, and region.</li>
<li>Click the <code>Review + create</code> button.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf2kmh12t8eucd1qa1pg.png" alt="Form for creating a web app in Azure" width="600" height="400" loading="lazy">
<em>Creating a Web App in Azure</em></p>
<h3 id="heading-deploy-the-application">Deploy the Application</h3>
<p>The Web App takes a couple of minutes to create. Once done, you can deploy your Spring Boot application to Azure App Service.</p>
<p>One of the easiest ways to deploy is to package your Spring Boot application as a JAR file and deploy it to Azure App Service using the Azure CLI.</p>
<p>To do this, run the below commands:</p>
<pre><code>mvn package
az webapp deploy --src-path neon-demo<span class="hljs-number">-0.0</span><span class="hljs-number">.1</span>-SNAPSHOT.jar --resource-group learn-ba1a439c<span class="hljs-number">-71</span>ca<span class="hljs-number">-4</span>cab<span class="hljs-number">-9</span>bb1-f5b1331bab04 --name neon-app
</code></pre><p>Here, you're packaging your Spring Boot application using Maven and deploying the JAR file to Azure App Service using the Azure CLI. You've provided the path to the JAR file, the resource group, and the app name you previously configured.</p>
<h3 id="heading-access-the-application">Access the Application</h3>
<p>Once the deployment is complete, you can access your Spring Boot application on Azure App Service by navigating to the URL of the Web App. Your app is available at neon-app.azurewebsites.net</p>
<p>Let's use _curl _to test the endpoints.</p>
<h4 id="heading-create-a-user">Create a User</h4>
<pre><code>curl -X POST -d <span class="hljs-string">'{"name":"John Doe","email":"john@gmail.com"}'</span> https:<span class="hljs-comment">//neon-app.azurewebsites.net/users</span>
</code></pre><p>Here you provide user data in JSON format to create a new user.</p>
<h4 id="heading-get-users">Get Users</h4>
<p>You can also can test that the user was created by fetching all users:</p>
<pre><code>curl -X GET https:<span class="hljs-comment">//neon-app.azurewebsites.net/users</span>
</code></pre><h2 id="heading-how-to-set-up-autoscaling">How to Set Up Autoscaling</h2>
<p>A production application may experience varying levels of traffic, and it's important to scale the application dynamically based on the load.</p>
<p>Let's explore how you can autoscale your application when needed.</p>
<h3 id="heading-autoscaling-in-azure">Autoscaling in Azure</h3>
<p>Azure App Service provides <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal#plan-and-sku-settings">autoscaling options</a> that let you automatically adjust the number of instances as needed.</p>
<p>You can configure autoscaling rules in the Azure portal by following these steps:</p>
<ul>
<li>Navigate to the Web App in the Azure portal.</li>
<li>Click the <code>Scale out (App Service Plan)</code> option from the left menu.</li>
<li>Configure the autoscaling rules – you can choose predefined rules like traffic or create custom rules based on metrics like CPU usage, memory usage, or custom metrics.</li>
<li>Save.</li>
</ul>
<p>Azure will automatically scale the application based on the configured rules.</p>
<h3 id="heading-autoscaling-in-neon">Autoscaling in Neon</h3>
<p>Since your application is automatically scaled based on the load, you'll want to ensure that the database can handle the increased traffic.</p>
<p>Neon provides <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">autoscaling options</a> to scale the database dynamically based on the load. You can configure autoscaling rules in the Neon dashboard to ensure the database can handle the increased load.</p>
<p>Follow the below steps to configure autoscaling in Neon:</p>
<ol>
<li>Navigate to the Neon dashboard and select the database. Then select the branch to configure autoscaling.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6s84pqhk2avflpjbgrf.png" alt="Neon project dashboard with branches section highlighted " width="600" height="400" loading="lazy">
<em>Selecting a branch from Neon project dashboard</em></p>
<ol start="2">
<li>Click on the <code>Edit</code> button next to the <code>Compute</code> section. Configure the autoscaling rules based on metrics like CPU usage, memory usage, or custom metrics.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkn11nop1zz9xxbfamsr.png" alt="Branch details view in Neon with edit button in the computes section highlighted" width="600" height="400" loading="lazy">
<em>Branch details view in Neon</em></p>
<ol start="3">
<li>Configure the min-max compute size and Save. Neon will automatically scale the database based on the configured rules when needed.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmuow8zvndz0dibv2kxt.png" alt="Form to enable autoscaling and select min and max size of the compute" width="600" height="400" loading="lazy">
<em>Setting up autoscaling for compute</em></p>
<p>Ensuring that both the application and the database can scale dynamically based on the load will help you handle varying levels of traffic efficiently.</p>
<h2 id="heading-how-to-configure-database-branches-in-neon">How to Configure Database Branches in Neon</h2>
<p>In a typical development workflow, multiple databases may be used for different purposes like development, testing, and production.</p>
<p>Neon Postgres provides <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">database branching</a> to create multiple branches for different purposes. Each branch is an instance of the database that you can use independently.</p>
<p>This Git-like feature helps set up a copy of the database for different environments like development, staging, and production. It also helps preserve data for different versions of the application.</p>
<p>Let's explore how you can create and manage branches in Neon Postgres:</p>
<ul>
<li>Navigate to the Neon dashboard and select the database.</li>
<li>In the <code>Branches</code> section, click on the <code>View All</code> button.</li>
<li>You can create a new branch from an existing one by clicking on the <code>Create Branch</code> button. You'll need to provide the branch name and what data to copy from the parent branch.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ncdgdrj32etd3gbqurf.png" alt="Branches view with Create branch option visible " width="600" height="400" loading="lazy">
<em>Create branch option</em></p>
<ul>
<li>You can either copy all the data or copy until a point in time or a specific record. This is useful for multiple purposes like restoring data, creating a new environment, or testing new features.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7gchucru5qw294icqw3.png" alt="Creating a new branch from an existing branch" width="600" height="400" loading="lazy">
<em>Creating a new branch</em></p>
<ul>
<li>Neon will create a new branch of the database that can be used independently. You can find the URL, username, and password for the new branch in the dashboard. And this happens in real time without any downtime and delays.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji79akuf193gtv94yaag.png" alt="Branch-specific connection details " width="600" height="400" loading="lazy">
<em>Branch-specific connection details</em></p>
<p>Now you can use your <code>dev</code> branch for local development and testing, and the <code>main</code> branch for production. This helps in keeping the data separate and ensures that changes in one branch do not affect the other branches.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we built a CRUD application using Spring Boot, Neon Postgres, and Azure App Service.</p>
<p>We explored how to set up the Neon Postgres database, build a basic CRUD application using Spring Boot, deploy the application on Azure App Service, and configure autoscaling for the application and the database.</p>
<p>We also learned about how the database branching feature in Neon Postgres helps you create branches of the database for different environments and purposes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Azure CosmosDB – Database Guide for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we will go through the basics of Azure Cosmos DB and understand the configuration options available with it.  We will cover resource management concepts, data model, APIs, and configuration options. 1. What is Azure Cosmos DB? Azure ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-beginners-guide-to-azure-cosmosdb/</link>
                <guid isPermaLink="false">66c3761fe912451bdfbe18d5</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhinav Pandey ]]>
                </dc:creator>
                <pubDate>Wed, 22 Jun 2022 23:37:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/06/1_mGWQfH9O34wfTQ-cpng7ZA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we will go through the basics of Azure Cosmos DB and understand the configuration options available with it. </p>
<p>We will cover resource management concepts, data model, APIs, and configuration options.</p>
<h2 id="heading-1-what-is-azure-cosmos-db"><strong>1. What is Azure Cosmos DB?</strong></h2>
<p>Azure Cosmos DB is a document database service that enables us to store, query, and index our data in a highly available, globally consistent, and scalable cloud-based NoSQL database. </p>
<p>It is fully managed which means availability, reliability, and security are all handled for us.</p>
<h3 id="heading-cosmos-db-apis"><strong>Cosmos DB APIs</strong></h3>
<p>The standout feature of Cosmos DB is that you can configure it to use either SQL or NoSQL to interact with your data. It does so by providing different APIs for each type of data you want to store. </p>
<p>The APIs are:</p>
<ol>
<li><strong>SQL API</strong> – for storing and querying data using an SQL-like syntax. This is the default and recommended API.</li>
<li><strong>Gremlin API</strong> – if we want to interact with data using a graph database-like syntax.</li>
<li><strong>Table API</strong> – for applications migrating from Azure Table Storage to Cosmos DB.</li>
<li><strong>Cassandra API</strong> – for working with data designed for the Cassandra database.</li>
<li><strong>MongoDB API</strong> – for working with data designed for the MongoDB database.</li>
</ol>
<p>By providing these APIs, Cosmos DB makes it easy for us to migrate from an existing data store to Cosmos DB. More on this when we explore how to connect to Cosmos DB programmatically.</p>
<p>Note that the APIs do not determine how the data is stored. The data is stored in a NoSQL database.</p>
<h3 id="heading-why-choose-cosmos-db"><strong>Why Choose Cosmos DB?</strong></h3>
<p>Since there are other cloud-based databases which you can use to store data, it is important to understand why you might want to migrate to Cosmos DB.</p>
<p>Cosmos DB provides some premium capabilities that may not be available in other cloud-based databases:</p>
<ul>
<li>Easy global distribution of data – which increases availability and speed with multi-region write and read operations.</li>
<li>Dedicated throughput</li>
<li>Single digit millisecond latency.</li>
<li>Guaranteed availability</li>
<li>Advanced indexing and partitioning</li>
</ul>
<p>and more.</p>
<p>In addition to this, the APIs make it easier to switch between different database approaches without physically migrating data.</p>
<h2 id="heading-2-basic-azure-cosmos-db-concepts"><strong>2. Basic Azure Cosmos DB Concepts</strong></h2>
<p>Let's look at some basic concepts of Azure Cosmos DB.</p>
<h3 id="heading-resource-hierarchy"><strong>Resource Hierarchy</strong></h3>
<p>Below is the resource hierarchy of Azure Cosmos DB.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-156.png" alt="Cosmos DB Resource Hierarchy Diagram. Heirarchy is as follows: Account contains Databases. Databases contain containers. Containers contain Items and other resources." width="600" height="400" loading="lazy">
<em>Cosmos DB resource Hierarchy</em></p>
<p>Let's understand each level and the configurations available at the different levels of the hierarchy.</p>
<h4 id="heading-cosmos-account"><strong>Cosmos Account</strong></h4>
<p>A Cosmos Account is the top level resource in Azure Cosmos DB. It is the entry point to our Cosmos DB instances.</p>
<p>The following features are defined at the Cosmos Account level:</p>
<ol>
<li>A unique DNS name used to connect with database instances like https://{account}.documents.azure.com/</li>
<li>Global distribution capabilities – you can define how many regions you want to distribute your data across.</li>
<li>The default consistency level for all resources in the account. You can override this for individual resources.</li>
</ol>
<h4 id="heading-databases-and-containers"><strong>Databases and Containers</strong></h4>
<p>An account can contain multiple databases which have the same distribution needs. Each database can contain multiple containers. You can also use databases to manage users, permissions, and throughput for underlying containers.</p>
<p><strong>Each container is analogous to a table in SQL, collection in MongoDB, graph in Gremlin, and so on.</strong> Containers are fundamental units of scalability for storage and throughput. They are horizontally partitioned and replicated across multiple regions as defined by the account.</p>
<p>The throughput of a container can be defined in two ways:</p>
<ol>
<li><strong>Dedicated provisioned throughput mode</strong> – Each container instance can be assigned a fixed throughput. Costlier and backed by SLAs.</li>
<li><strong>Shared provisioned throughput mode</strong> – The total throughput of all container instances running in shared mode remains the same while individual containers can have different real-time throughputs.</li>
</ol>
<p>At the container level, we also have the option to configure the indexing policy and default TTL.</p>
<h4 id="heading-contents-of-a-container"><strong>Contents of a Container</strong></h4>
<p>Similar to an SQL table, a container can contain multiple resources. The most important resource is the Item(s).</p>
<p><strong>An item is a single unit of record.</strong> For example, a row in a table, a document in a collection, a node in a graph, and so on.</p>
<p>Some other resources include JavaScript based:</p>
<ol>
<li>Stored procedures</li>
<li>User-defined functions</li>
<li>Triggers</li>
</ol>
<h3 id="heading-consistency-levels"><strong>Consistency levels</strong></h3>
<p>Data can be replicated across multiple regions and writes can be allowed. In such scenarios, determining the consistency requirements of the data is important.</p>
<p>Let's look at the different consistency levels available in Azure Cosmos DB and what they mean:</p>
<ol>
<li><strong>Strong</strong> – Data remains exactly the same across all regions. This means that the write operation is expensive and does not complete until all regions have the data.</li>
<li><strong>Bounded Staleness</strong> – The delay in the write operation is bounded by a fixed time interval between the regions. For example, after a write operation is performed, the data is guaranteed to be available in the next <em>t</em> seconds.</li>
<li><strong>Session</strong> – Data written in a session will be available to read when a read is performed in the same session. This is good when for a user session, all reads and writes are taken care of by a single region.</li>
<li><strong>Consistent Prefix</strong> – Data will be read in the same sequence in which it is written. For example, if in region 1 we write data A and then B, then in region 2, A will be available before B.</li>
<li><strong>Eventual</strong> – Both order and staleness do not matter, the only thing important is that data will be eventually available in all regions. Works fast but has the least consistency.</li>
</ol>
<p><strong>Explore</strong> – Scenarios that require different consistency levels.</p>
<h3 id="heading-request-units-rus"><strong>Request Units (RUs)</strong></h3>
<p>According to the definition on Microsoft Learn:</p>
<blockquote>
<p>The cost to do a point read, which is fetching a single item by its ID and partition key value, for a 1KB item is 1RU.</p>
</blockquote>
<p>The cost is based on system resources such as CPU, IOPS, and memory that are required to perform the database operations. RUs consumed by our application are eventually billed to the account. There are different modes in which the Cosmos account can be set up which will affect billing:</p>
<ol>
<li><strong>Provisioned throughput mode</strong> – Set up the expected throughput in terms of RUs per second. The mode is chosen at the account level but the RUs can be provisioned at the database or container level.</li>
<li><strong>Serverless mode</strong> – Pay for actual consumed units.</li>
<li><strong>Autoscale mode</strong> – The account is set up to scale automatically based on the usage. This is good for applications with variable or unpredictable usage.</li>
</ol>
<h3 id="heading-database-partitioning"><strong>Database Partitioning</strong></h3>
<p>As mentioned earlier in the container section, a container can be partitioned into multiple partitions. You do this by setting the partition key.</p>
<h4 id="heading-partitions-and-indexes"><strong>Partitions and Indexes</strong></h4>
<ul>
<li><strong>Logical Partitions</strong></li>
</ul>
<p>A logical partition is a collection of items that share the same partition key value. For example, if a container called "Users" is partitioned by a key "State", then a logical partition is a collection of items that share the same "State" value.</p>
<ul>
<li><strong>Index</strong></li>
</ul>
<p>Indexes are used to improve the performance of queries. In a regular SQL database, an index is created by default based on a primary key. Cosmos DB items also contain a unique field called Item ID. </p>
<p><strong>The default index in Cosmos DB is a combination of the partition key and the item ID.</strong> Partition key is used to locate the logical partition and the item ID is used to locate the specific item. Thus, for faster access, it is important to choose a good partition key which distributes the data evenly across the partitions.</p>
<ul>
<li><strong>Physical Partitions</strong></li>
</ul>
<p>The role of physical partitions is to provide horizontal scalability. A physical partition is a collection of one or more logical partitions. Data from a single logical partition cannot exist across more than one physical partition. </p>
<p><strong>The user does not have any control over how the data is distributed across the physical partitions.</strong> Cosmos DB is a managed service and the system will automatically distribute the data across the physical partitions when scalability is needed. </p>
<p>This forms the basis of another guideline that partitioning keys should lead to smaller logical partitions. If logical partitions are too large, it will affect the limit to which the system can scale.</p>
<h4 id="heading-how-to-choose-a-partition-key"><strong>How to Choose a Partition Key</strong></h4>
<p>By now, we know what a partition key is. But how do we choose a good partition key? Here are a few guidelines:</p>
<ol>
<li><strong>Immutable</strong> – The partition key cannot be changed after the data is created.</li>
<li><strong>High Cardinality</strong> – A large number of possible values for the partition key will lead to a large number of small logical partitions. Good for indexing and scalability.</li>
<li><strong>Even Distribution</strong> – Apart from high cardinality, it is also important that each possible value is equally likely. This is good for even distribution of data across the partitions.</li>
<li><strong>Read heavy containers</strong> – For read heavy containers, it's important to choose a partition key that appears frequently in the read queries. Otherwise, the benefit of partition key based index will be lost. It is also beneficial that most queries can read data from a single partition and cross-partition queries are minimized.</li>
<li><strong>Using Item ID as a Partition Key</strong> – Cosmos DB supports a unique field called Item ID. This field is automatically generated and is guaranteed to be unique. This is a good choice for partition keys.</li>
</ol>
<p><strong>Explore</strong> – Why not use Item ID as a partition key?</p>
<p>Here's some more info on <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cosmos-db/partitioning-overview#choose-partitionkey">choosing a partition key</a>.</p>
<h4 id="heading-synthetic-partition-keys"><strong>Synthetic Partition Keys</strong></h4>
<ul>
<li>Concatenate multiple fields together to create a partition key.</li>
<li>Use a hash function to create a partition key suffix.</li>
<li>Use a random string to create a partition key suffix.</li>
</ul>
<h2 id="heading-3-cosmos-db-data-model"><strong>3. Cosmos DB Data Model</strong></h2>
<p>As mentioned earlier, all data in CosmosDB is store in a NoSQL way. Let's look at some aspects of the data model. </p>
<h3 id="heading-document-data-model"><strong>Document Data Model</strong></h3>
<p>In a document data model, each entry is called a document. In Cosmos DB terminology, documents can be referred to as items.</p>
<p>A document-oriented database will have the below characteristics:</p>
<ul>
<li><strong>Non-relational</strong> – Each item is an individual entity.</li>
<li><strong>Easy to scale out</strong> – It is possible to create physical partitions for the data to improve performance and to scale storage.</li>
<li><strong>No schema</strong> – The database in itself won't enforce any schema. This gives the flexibility to store entities of different data formats. It also helps the structure evolve over time.</li>
</ul>
<h3 id="heading-items"><strong>Items</strong></h3>
<p>Each <em>item</em> in Cosmos DB is a JSON document. Write operations on these documents are atomic. Items contain a unique <em>Item ID</em> and a <em>partition key</em> which is used to partition the data across multiple logical partitions.</p>
<p>Partition keys can also be nested fields. For example, in the below JSON, <em>city</em> field can be used as a partition key even if it is not at the root level.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"1"</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John"</span>,
    <span class="hljs-attr">"address"</span>: {
        <span class="hljs-attr">"street"</span>: <span class="hljs-string">"1 Main St"</span>,
        <span class="hljs-attr">"city"</span>: <span class="hljs-string">"New York"</span>
    }
}
</code></pre>
<p>While creating containers, it is mandatory to provide the partition key path. In the above example, the path will be <code>/address/city</code>.</p>
<h2 id="heading-4-how-to-configure-cosmos-db"><strong>4. How to Configure Cosmos DB</strong></h2>
<p>In Cosmos DB, the SQL API is a query language that allows us to query data in a document database using SQL-like syntax. There are many reasons to choose the SQL API over other APIs:</p>
<ul>
<li>Low latency</li>
<li>Automatic scaling</li>
<li>99.999% availability backed by SLAs</li>
</ul>
<p>It is well suited for high-performance applications like:</p>
<ul>
<li>Collecting and querying data from IoT devices – which generates a lot of data and needs to be processed quickly.</li>
<li>Retail applications – which have varied usage patterns and can benefit from elastic scaling.</li>
<li>Multi-platform applications – which can benefit from flexibility in document structure.</li>
</ul>
<h3 id="heading-throughput-provisioning"><strong>Throughput Provisioning</strong></h3>
<p>When configuring Azure Cosmos DB, we can provision throughput at either or both the database and container levels.</p>
<h4 id="heading-container-level-throughput"><strong>Container Level Throughput</strong></h4>
<p>A throughput provisioned at container level applies only to the container. It does not impact other containers of the database. For example, in the below image, each container has a different throughput.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/2-container.png" alt="Container level throughput provisioning. Shows 3 containers. Each have a different RU per second set." width="600" height="400" loading="lazy">
<em>Container-level throughput provisioning</em></p>
<p>This is the recommended way to provision throughput. If each container is mapped to a separate application function, then it makes sense to provision throughput at container level.</p>
<h4 id="heading-database-level-throughput"><strong>Database Level Throughput</strong></h4>
<p>We can also provision throughput at the database level. This will be shared across all containers in the database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/2-database.png" alt="Database Level Throughput Provisioning. Image shows throughput of 10000 RU/s configured on the database and shared by its containers" width="600" height="400" loading="lazy">
<em>Database Level Throughput Provisioning</em></p>
<p>This is fine if all containers are expected to have similar load patterns but in most cases, it'll lead to unpredictable results.</p>
<h4 id="heading-mixed-throughput"><strong>Mixed Throughput</strong></h4>
<p>It is possible to mix container and database level throughput provisioning. To do so, we first define a throughput at the database level. Then, while creating a container, we can specify which throughput mode to use.</p>
<p>Containers configured in shared throughput mode will share the throughput provisioned at the database level. Containers configured in dedicated throughput mode will have their own throughput provisioned at the container level.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/2-mixed.png" alt="Mixed throughput provisioning. Image shows throughput of 6000 RU/s configured at Database level and shared by its containers except for one container which has its own throughput of 2000 RU/s" width="600" height="400" loading="lazy">
<em>Mixed throughput provisioning</em></p>
<p>Note that we cannot convert a container from shared to dedicated throughput mode or vice versa. To change this, we need to delete the container and create a new one.</p>
<h3 id="heading-storage"><strong>Storage</strong></h3>
<p>To estimate storage requirements, we can use the Azure Cosmos DB Capacity Calculator.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/4-calculator.png" alt="Cosmos DB Capacity Calculator. A form showing multiple fields like API, IO requirements, data estimate, replication, etc. Based on these values entered by the user, a cost estimate is created on the right side." width="600" height="400" loading="lazy">
<em>Cosmos DB Capacity Calculator</em></p>
<p>After entering the estimated load, replication strategy, and storage requirements, the calculator can provide an estimated cost of such a setup.</p>
<h3 id="heading-time-to-live-ttl"><strong>Time to Live (TTL)</strong></h3>
<p>It is possible to set a time-to-live (TTL) on documents in a container. This is useful for documents that are expected to be deleted in a short period of time. It can be configured at the container level and can be overridden at the document level. The maximum TTL value is 2147483647.</p>
<p>At the container level, TTL needs to be set to one of the below values:</p>
<ol>
<li><strong>Does Not Exist</strong> – No TTL and no expiration even if trying to set TTL on a document.</li>
<li><strong>-1</strong> – No TTL by default but can be added at the document level.</li>
<li><strong>Number of seconds</strong> – Default TTL is the provided number of seconds. This can be overridden at the document level.</li>
</ol>
<p>Expiring documents and optimizing the storage consumed can result in better performance and lower costs. So it's important to decide which TTL value to use and which items to expire. </p>
<p>Some solutions may require Cosmos DB as an intermediate storage to perform queries and pass the results to the final storage. In this case, you should use TTLs to expire documents as soon as possible to minimize cost.</p>
<h3 id="heading-cosmos-db-consumption-models"><strong>Cosmos DB Consumption Models</strong></h3>
<p>Let's take a look at the different consumption models in detail.</p>
<h4 id="heading-serverless"><strong>Serverless</strong></h4>
<p>In Serverless model, the service is billed according to the actual number of RUs consumed. This is great when the consumption pattern is unpredictable and can depend of factors like campaigns, feature releases, time of the day, seasonal sales, holidays, and so on.</p>
<p>It is also great in situations when:</p>
<ol>
<li>A new application is launched and we don't have much load to start with. We also don't know how the load will grow. </li>
<li>The DB supports a serverless application hosted on Azure Functions. As the application gets more users, the DB will also get more requests. </li>
<li>Getting started with Cosmos DB and not having a lot of experience with provisioning and cost.</li>
<li>The service is not expected to scale and will likely consume less than the minimum configurable RUs.</li>
</ol>
<h4 id="heading-provisioned-vs-serverless"><strong>Provisioned vs Serverless</strong></h4>
<p>Deciding between Serverless and Provisioned consumption model is a trade-off between cost and performance. Use the below points to help you decide:</p>
<ol>
<li>The workload – predictable and sufficiently large workload favours provisioned consumption model.</li>
<li>RU limiting – Provisioned throughput will not exceed the maximum decided RU while Serverless can scale up to the maximum possible RUs/s allowed in Cosmos DB. When expecting burst situations, you can use Serverless.</li>
<li>Global Distribution – This is an important factor. Serverless models are not distributed across regions and so can be used for a single region. Provisioned models are distributed across regions and can be used for multiple regions.</li>
<li>Storage Limits – Serverless only stores 50 GB of data per container while Provisioned can store unlimited data per container.</li>
</ol>
<h4 id="heading-auto-scale-model"><strong>Auto-Scale Model</strong></h4>
<p>Auto-Scale model finds the balance between provisioned and serverless consumption models. It works by dynamically provisioning resources as needed but within a specified range.</p>
<p>Let's look at a comparison between auto-scale and provisioned throughput:</p>
<ol>
<li><strong>The workload</strong> – Auto-scale throughput oscillates between the minimum acceptable performance and the maximum cost we want to incur. Provisioned is still better if the workload is predictable because we neither want to lose out on performance nor incur more costs in the long run.</li>
<li><strong>RU consumption</strong> – With auto-scale, we can set an RU limit same as with provisioned. The difference is that provisioned billing is always done on the RUs specified but auto-scale billing is based on – the RUs consumed in real-time or 10% of the provisioned RUs – whichever is higher. Keeping this in mind, it's recommended to use provisioned consumption model only if the actual consumption is close to the provisioned limit for more than 66% of the time.</li>
</ol>
<p>It is also possible to migrate containers from auto-scale to provisioned throughput and vice versa. During the migration, a RU value is automatically chosen by the system and must be verified or manually set after the migration.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Thanks for reading. This should give you some idea of how Azure's CosmosDB service works and how to configure it. If you want to connect with me, you can find me on <a target="_blank" href="https://www.twitter.com/abh1navv">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Rate Limiter using Bucket4J and Redis ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial we will learn how to implement rate limiting in a scaled service.We will use the Bucket4J library to implement it and we will use Redis as a distributed cache. Why Use Rate Limiting? Let's get started with some basics to make sure we... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rate-limiting-with-bucket4j-and-redis/</link>
                <guid isPermaLink="false">66c37625f278f15f931a342a</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhinav Pandey ]]>
                </dc:creator>
                <pubDate>Fri, 01 Apr 2022 19:05:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/Rate-Limiter-with-Bucket4J-and-Redis.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial we will learn how to implement rate limiting in a scaled service.<br>We will use the <a target="_blank" href="https://github.com/vladimir-bukhtoyarov/bucket4j">Bucket4J</a> library to implement it and we will use <a target="_blank" href="https://redis.io/">Redis</a> as a distributed cache.</p>
<h2 id="heading-why-use-rate-limiting">Why Use Rate Limiting?</h2>
<p>Let's get started with some basics to make sure we understand the need for rate limiting and introduce the tools we'll be using in this tutorial.</p>
<h3 id="heading-problem-with-unlimited-rates">Problem with Unlimited Rates</h3>
<p>If a public API like the Twitter API allowed its users to make an unlimited number of requests per hour, it could lead to:</p>
<ul>
<li>resource exhaustion</li>
<li>decreasing quality of the service</li>
<li>denial of service attacks</li>
</ul>
<p>This might result in a situation where the <strong>service is unavailable or slow</strong>. It could also lead to more <strong>unexpected costs</strong> being incurred by the service.</p>
<h3 id="heading-how-rate-limiting-helps">How Rate Limiting Helps</h3>
<p>Firstly, rate-limiting can prevent denial of service attacks. When coupled with a deduplication mechanism or API keys, rate limiting can also help prevent distributed denial of service attacks.</p>
<p>Secondly, it helps in estimating traffic. This is very important for public APIs. This can also be coupled with automated scripts to monitor and scale the service.</p>
<p>And thirdly, you can use it to implement tier-based pricing. This type of pricing model means that users can pay for a higher rate of requests. The Twitter API is an example of this.</p>
<h3 id="heading-the-token-bucket-algorithm">The Token Bucket Algorithm</h3>
<p>Token Bucket is an algorithm that you can use to implement rate limiting. In short, it works as follows:</p>
<ol>
<li>A bucket is created with a certain capacity (number of tokens).</li>
<li>When a request comes in, the bucket is checked. If there is enough capacity, the request is allowed to proceed. Otherwise, the request is denied.</li>
<li>When a request is allowed, the capacity is reduced.</li>
<li>After a certain amount of time, the capacity is replenished.</li>
</ol>
<h3 id="heading-how-to-implement-token-bucket-in-a-distributed-system">How to Implement Token Bucket in a Distributed System</h3>
<p>To implement the token bucket algorithm in a distributed system, we need to use a <strong>distributed cache</strong>.</p>
<p>The cache is a <strong>key-value store</strong> to store the bucket information. We will use a Redis cache to implement this.</p>
<p>Internally, Bucket4j allows us to plug in any implementation of the Java JCache API. The <a target="_blank" href="https://redisson.org/">Redisson</a> client of Redis is the implementation we will use.</p>
<h2 id="heading-project-implementation">Project Implementation</h2>
<p>We will use the <a target="_blank" href="https://spring.io/projects/spring-boot">Spring Boot</a> framework to build our service.</p>
<p>Our service will contain the below components:</p>
<ol>
<li>A simple REST API.</li>
<li>A Redis cache connected to the service – using the Redisson client.</li>
<li>The Bucket4J library wrapped around the REST API.</li>
<li>We'll connect Bucket4J to the JCache interface which will use the Redisson client as the implementation in the background.</li>
</ol>
<p>First, we will learn to rate limit the API for all requests. Then we will learn to implement a more complex rate limiting mechanism per user or per pricing tier.</p>
<p>Let's start with the project setup.</p>
<h3 id="heading-install-dependencies">Install Dependencies</h3>
<p>Let's add the below dependencies to our <em>pom.xml</em> (or <em>build.gradle</em>) file.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- To build the Rest API --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Redisson Starter = Spring Data Redis starter(excluding other clients) and Redisson client --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.redisson<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>redisson-spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.17.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Bucket4J starter = Bucket4J + JCache --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.giffing.bucket4j.spring.boot.starter<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>bucket4j-spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.5.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>
</code></pre>
<h3 id="heading-cache-configuration">Cache Configuration</h3>
<p>Firstly, we need to start our Redis server. Let's say we have a Redis server running on port 6379 on our local machine.</p>
<p>We need to perform two steps:</p>
<ol>
<li>Create a connection to this server from our application.</li>
<li>Set up JCache to use the Redisson client as the implementation.</li>
</ol>
<p><a target="_blank" href="https://github.com/redisson/redisson/wiki/14.-Integration-with-frameworks/#144-jcache-api-jsr-107-implementation">Redisson's documentation</a> provides concise steps to implement this in a regular Java application. We're going to implement the same steps, but in Spring Boot.</p>
<p>Let's look at the code first. We need to create a Configuration class to create the required beans.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RedisConfig</span>  </span>{

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Config <span class="hljs-title">config</span><span class="hljs-params">()</span> </span>{
        Config config = <span class="hljs-keyword">new</span> Config();
        config.useSingleServer().setAddress(<span class="hljs-string">"redis://localhost:6379"</span>);
        <span class="hljs-keyword">return</span> config;
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CacheManager <span class="hljs-title">cacheManager</span><span class="hljs-params">(Config config)</span> </span>{
        CacheManager manager = Caching.getCachingProvider().getCacheManager();
        cacheManager.createCache(<span class="hljs-string">"cache"</span>, RedissonConfiguration.fromConfig(config));
        <span class="hljs-keyword">return</span> cacheManager;
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function">ProxyManager&lt;String&gt; <span class="hljs-title">proxyManager</span><span class="hljs-params">(CacheManager cacheManager)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> JCacheProxyManager&lt;&gt;(cacheManager.getCache(<span class="hljs-string">"cache"</span>));
    }
}
</code></pre>
<p><strong>What does this do?</strong></p>
<ol>
<li>Creates a configuration object that we can use to create a connection.</li>
<li>Creates a cache manager using the configuration object. This will internally create a connection to the Redis instance and create a hash called "cache" on it.</li>
<li>Creates a proxy manager that will be used to access the cache. Whatever our application tries to cache using the JCache API, it will be cached on the Redis instance inside the hash named "cache".</li>
</ol>
<h3 id="heading-build-the-api">Build the API</h3>
<p>Let's create a simple REST API.</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimitController</span> </span>{
    <span class="hljs-meta">@GetMapping("/user/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getInfo</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable("id")</span> String id)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello "</span> + id;
    }
}
</code></pre>
<p>If I hit the API with the URL <code>http://localhost:8080/user/1</code>, I will get the response <code>Hello 1</code>.</p>
<h3 id="heading-bucket4j-configuration">Bucket4J Configuration</h3>
<p>To implement the rate limiting, we need to configure Bucket4J. Thankfully, we do not need to write any boilerplate code due to the starter library.</p>
<p>It also <strong>automatically detects the ProxyManager bean</strong> we created in the previous step and uses it to cache the buckets.</p>
<p>What we do need to do is configure this library around the API we created.<br>Again there are multiple ways to do this.</p>
<p>We can go for <a target="_blank" href="https://github.com/MarcGiffing/bucket4j-spring-boot-starter#configuration-via-properties">property-based configuration</a> which is defined in the starter library.<br>This is the most convenient way for simple cases like rate-limiting for all users or all guest users.</p>
<p>However, if we want to implement something more complex like a rate limit for each user, it's better to write custom code for it.</p>
<p>We are going to implement rate limiting per user. Let's assume we have the rate limit for each user stored in a database, and we can query it using the user id.</p>
<p>Let's write the code for it step by step.</p>
<h4 id="heading-create-a-bucket">Create a Bucket</h4>
<p>Before we start, let's look at how a bucket is created.</p>
<pre><code class="lang-java">Refill refill = Refill.intervally(<span class="hljs-number">10</span>, Duration.ofMinutes(<span class="hljs-number">1</span>));
Bandwidth limit = Bandwidth.classic(<span class="hljs-number">10</span>, refill);
Bucket bucket = Bucket4j.builder()
        .addLimit(limit)
        .build();
</code></pre>
<ul>
<li><strong>Refill</strong> – After how much time the bucket will be refilled.</li>
<li><strong>Bandwidth</strong> – How much bandwidth the bucket has. Basically, requests per refill period.</li>
<li><strong>Bucket</strong> – An object configured using these two parameters. Additionally, it maintains a token counter to keep track of how many tokens are available in the bucket.</li>
</ul>
<p>Using this as the building block, let's change a few things to make it suitable to our use case.</p>
<h4 id="heading-create-and-cache-buckets-using-proxymanager">Create and Cache Buckets using ProxyManager</h4>
<p>We created the proxy manager for the purpose of storing buckets on Redis. Once a bucket is created, it needs to be cached on Redis and does not need to be created again.</p>
<p>To make this happen, we will replace the <code>Bucket4j.builder()</code> with <code>proxyManager.builder()</code>. ProxyManager will take care of caching the buckets and not creating them again.</p>
<p>ProxyManager's builder takes two parameters – a <strong>key</strong> against which the bucket will be cached and a <strong>configuration object</strong> that it will use to create the bucket.</p>
<p>Let's see how we can implement it:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimiter</span> </span>{
    <span class="hljs-comment">//autowiring dependencies</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> Bucket <span class="hljs-title">resolveBucket</span><span class="hljs-params">(String key)</span> </span>{
        Supplier&lt;BucketConfiguration&gt; configSupplier = getConfigSupplierForUser(key);

        <span class="hljs-comment">// Does not always create a new bucket, but instead returns the existing one if it exists.</span>
        <span class="hljs-keyword">return</span> buckets.builder().build(key, configSupplier);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Supplier&lt;BucketConfiguration&gt; <span class="hljs-title">getConfigSupplierForUser</span><span class="hljs-params">(String key)</span> </span>{
        User user = userRepository.findById(userId);
        Refill refill = Refill.intervally(user.getLimit(), Duration.ofMinutes(<span class="hljs-number">1</span>));
        Bandwidth limit = Bandwidth.classic(user.getLimit(), refill);
        <span class="hljs-keyword">return</span> () -&gt; (BucketConfiguration.builder()
                .addLimit(limit)
                .build());
    }
}
</code></pre>
<p>We have created a method which returns a bucket for a key provided. In the next step, we will see how to use this.</p>
<h4 id="heading-how-to-consume-tokens-and-set-up-rate-limiting">How to Consume Tokens and Set Up Rate Limiting</h4>
<p>When a request comes in, we will try to consume a token from the relevant bucket.<br>We will use the <code>tryConsume()</code> method of the bucket to do this.</p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/user/{id}")</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getInfo</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable("id")</span> String id)</span> </span>{
    <span class="hljs-comment">// gets the bucket for the user</span>
    Bucket bucket = rateLimiter.resolveBucket(id);

    <span class="hljs-comment">// tries to consume a token from the bucket</span>
    <span class="hljs-keyword">if</span> (bucket.tryConsume(<span class="hljs-number">1</span>)) {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello "</span> + id;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Rate limit exceeded"</span>;
    }
}
</code></pre>
<p>The <code>tryConsume()</code> method returns <code>true</code> if the token was consumed successfully or <code>false</code> if the token was not consumed.</p>
<h2 id="heading-how-to-test-our-service">How to Test our Service</h2>
<p>We can test this using any automated testing technique. For example, we can use <a target="_blank" href="https://junit.org/">JUnit</a>. Let's write a test case that calls the <code>getInfo()</code> method multiple times and verifies that the response is correct.</p>
<p>Let's assume we have a user with id <code>1</code> and a limit of <code>10</code> requests per minute. Let's assume we also have a user with id <code>2</code> and a limit of <code>20</code> requests per minute.</p>
<p>We will hit 11 requests for both users and verify that the request fails for the user with id <code>1</code> but succeeds for the user with id <code>2</code>.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testGetInfo</span><span class="hljs-params">()</span> </span>{

    <span class="hljs-comment">// calls the method 10 times for user 1</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++) {
        rateLimiter.getInfo(<span class="hljs-number">1</span>));
        rateLimiter.getInfo(<span class="hljs-number">2</span>));
    }

    <span class="hljs-comment">// verifies that the response is rate limited for user 1</span>
    assertEquals(<span class="hljs-string">"Rate limit exceeded"</span>, rateLimiter.getInfo(<span class="hljs-number">1</span>));

    <span class="hljs-comment">// verifies that the response is successful for user 2</span>
    assertEquals(<span class="hljs-string">"Hello 2"</span>, rateLimiter.getInfo(<span class="hljs-number">2</span>));
}
</code></pre>
<p>When we run the test, we will see that the test passes.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we have covered how to create a rate limiter using Bucket4j and Redis in a Spring Boot application.We also looked at how to set up a Redisson client with JCache and how to use it to cache buckets.</p>
<p>At the end, we implemented a simple rate limiter which can be used to rate limit requests for specific users.</p>
<p>Hope you enjoyed this tutorial. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
