A Quick Guide to Feature Toggles in Spring Boot

Feature toggling is a powerful technique you can use to hide or disable parts of an application. Today, we’ll walk you through implementing a feature toggle (often called a feature flag) in Spring Boot. By the end of the post, you’ll have learned not only how to get started with toggles in practice, but also what they are in the first place and why they’re so useful.

Let’s dig in.

Feature Toggles in Spring Boot: The Fundamentals

Let’s start with a brief overview of both the concept of feature toggles and the main ways to implement them in a Spring Boot app. Feature toggles—also called feature flags or feature switches, among other names—are mechanisms that allow you to hide or disable features in your application.

Some could argue for primitive techniques such as disabling a portion of the code by commenting it out or even using a conditional. However, that’s not enough in practice, as you’ll soon see.

Turning Features Off and On Without Redeploying Code Is Handy …

A key property of an actual feature toggle is that it enables you to turn features off and on without having to change and redeploy the code. This capability is amazingly useful in a variety of scenarios.

… To Enable A/B Testing

One of the processes facilitated by the adoption of feature toggling is A/B testing.

In a nutshell, A/B testing is a technique to test how users react to a given feature. If you split users into two groups and serve each group a different version of the feature, you can identify which version generates the best user response.

Since feature toggles allow you to enable and disable features, you might be able to leverage them to enable a given feature only to a specific group of users at a time.

… To Facilitate Canary Releases

Another technique that feature toggles make easier is the canary release, which is sometimes mistaken for A/B testing. However, they’re two distinct techniques.

A canary release is a partial release. That means that you deploy your app’s new version just to a subset of your users, instead of all of them. Then, you closely monitor that group and roll back the release if something goes wrong. That way, if the changes have a defect, only a small percentage of your user base will experience it.

You might still think that does sound a little bit like A/B testing. So what’s the difference?

It’s simple: while A/B is mainly used to see how users respond to a given feature, a canary release is a risk-mitigating technique.

Feature toggles help canary releases in pretty much the same way they do with A/B testing. As explained before, while the main differences between A/B testing and canaries are the intentions behind each technique, the mechanisms that allow each one are mostly the same.

Spring Boot Feature Toggles: The Practical Guide

It’s finally time to roll up your sleeves and learn how to implement your first feature toggle. Let’s start by installing some requirements.

The sample app you’re going to add a feature flag to is a web API. So you’re going to need a tool like Postman to send HTTP requests.

I’ll be using the free community version of IntelliJ IDEA as my IDE throughout the tutorial.

Your next step is obtaining your key for the Split’s Java SDK. Start by signing up for a free Split account, and then log in. You’ll see a DE button in the upper left corner, which is the workspace button. Click on it, and then click on Admin settings.

After that, click on API Keys in the left panel. You’ll see the available keys for all of your environments. For this guide, you’ll use an SDK key for the staging-default environment. Just click on Copy, and the key will be available in your clipboard.

Find your API key to set up feature toggles in Spring Boot

Start Up the Sample App

The sample app for this tutorial is a web API that allows users to make reservations for a fictitious restaurant.

You can get it by going to this GitHub repo, either by cloning it or by downloading the code as a zip package. Save its contents to an easily accessible folder.

Then start IntelliJ IDEA. On the start screen, click on Open or Import. Then locate the folder containing the app’s source code. Select the pom.xml file and click OK. The IDE will ask you whether to open the pom.xml file as a project or as a regular file. Select Open as Project.

The project’s structure should look like this:

Spring Boot project structure

Open the DemoApplication class, and you’ll see two small play icons to the left of the code, one close to the class declaration and the other close to the method declaration. Click either one, and then click on Run > DemoApplication.main().

Finally, open your preferred browser, and go to localhost:8080/api/reservations. If everything went well, you should see something like this:

Run in localhost

You’ve just sent a GET request to the app’s endpoint, which resulted in an empty array, since you still haven’t added any reservations.

Create Reservations

Open the Postman application, and click on the new request button:

Create a reservation in your Spring Boot app with Postman

Postman will add a tab containing a new request. Change its type to POST, and add http://localhost:8080/api/reservations as the request URL. In the request options, click on Body, select raw as the type, and finally select JSON as the format.

Now, paste the following content to the request box, and then click on Send:

{ "name": "Julien Hamilton", "date": "2021-04-20", "quantity": 4, "email": "julien@example.com" }
Code language: JSON / JSON with Comments (json)

If everything went OK, you should see the 201 Created status code being displayed right below the request box.

Now, create a GET request to retrieve the reservation you’ve just created. Click the new request button again, enter the same address as the request URL, and leave the type as GET. Click Send and you should see the response in the form of the same data you sent plus a GUID:

Create a new GET request in your Spring Boot app

Enter the Need for a Feature Toggle

This API doesn’t implement many features a real application would. For instance, it doesn’t persist to a real database, storing the reservations in memory instead. Also, the number of seats available for each day is hard coded (as 40). A real-life application would allow that number to be configured via some external mechanism.

Another feature this app doesn’t have is a validation against creating reservations in the past. There’s nothing stopping us from adding a reservation to a date in, let’s say, 1995.

This is an important feature to have, so let’s implement it, using it as an opportunity to add a feature toggle to our application.

Time to Level Up: Use Split for Smarter Feature Toggle Management

The first thing you’ve got to do is add the Split SDK to the project. Since the app uses Maven, add the following to your pom.xml file, inside <dependencies>:

<dependency> <groupId>io.split.client</groupId> <artifactId>java-client</artifactId> <version>3.3.3</version> </dependency>
Code language: Django (django)

Wait for a few seconds while IntelliJ (through Maven) resolves the dependencies for the project. If that doesn’t work, try going to the Maven tab on Intellij IDEA and explicitly rebuilding the project. Then, try to build the application. If no errors happen, you’re ready to continue.

Change Your Code

Let’s now add the flag to the code. Right-click the com.example.demo package, go to New > Java class. Name the new class ReservationsAPIConfig. This is going to be a configuration class you’ll use to configure the bean for the Split client. Once the class is created, paste the following content in it:

@Configuration public class ReservationsAPIConfig { @Value("#{ @environment['split.api.key] }") private String apiKey; @Bean public SplitClient splitClient() throws Exception { SplitClientConfig config = SplitClientConfig.builder() .setBlockUntilReadyTimeout(20000) .enableDebug() .build(); SplitFactory splitFactory = SplitFactoryBuilder.build(apiToken, config); SplitClient client = splitFactory.client(); client.blockUntilReady(); return client; } }
Code language: Java (java)

In your src/main/resources folder, create a file called: application.yml and paste in the following:

split: api: key: <your split api key>
Code language: Swift (swift)

Note: replace <your split api key> with the actual split api key you copied earlier.

For the next step, you’ll have to go to the ReservationController and change its constructor so it gets an instance of SplitClient as a second argument. You’ll also need to add a new private field of type SplitClient.

public ReservationController(ReservationService reservationService, SplitClient splitClient) { this.reservationService = reservationService; this.splitClient = splitClient; }
Code language: Arduino (arduino)

The controller now has access to a Split client and can use it to decide whether or not reservations with dates in the paste should be refused.

To accomplish that, you’ll have to make some changes to the code. First, go to the ReservationService class. Here, replace the method tryCreateReservation with the following code:

public Optional<String> tryCreateReservation(Reservation reservation, boolean validatePastDate) { LocalDate today = clock.instant().atZone(clock.getZone()).toLocalDate(); if (validatePastDate && reservation.getDate().isBefore(today)) { return Optional.of("past-date"); } if (!canAccept(reservation)) return Optional.of("no-seats"); UUID id = UUID.randomUUID(); reservationRepository.insertReservation(id, reservation); return Optional.empty(); }
Code language: Arduino (arduino)

Now, go to the ReservationController class. Add a value parameter at the top of the class:

@Value("#{ @environment['split.api.treatement-name'] }") private String treatmentName;
Code language: Elixir (elixir)

Replace the method addNewReservation so it looks like this:

@PostMapping public void addNewReservation(@RequestBody Reservation reservation) { String treatment = splitClient.getTreatment("ANONYMOUS_USER", treatmentName); boolean validateAgainstPastDate; if (treatment.equals("on")) { validateAgainstPastDate = true; } else if (treatment.equals("off")) { validateAgainstPastDate = false; } else { throw new RuntimeException("Couldn't retrieve treatment from Split."); } Optional<String> errorMessage = reservationService.tryCreateReservation(reservation, validateAgainstPastDate); if (errorMessage.isPresent()) { String error = errorMessage.get(); String message = ""; HttpStatus status = HttpStatus.CREATED; if (error.equals("no-seats")) { message = "Couldn't accept: there aren't enough seats available."; status = HttpStatus.INTERNAL_SERVER_ERROR; } else if (error.equals("past-date")) { message = "The specified date is in the past."; status = HttpStatus.BAD_REQUEST; } throw new ResponseStatusException(status, message); } }
Code language: Arduino (arduino)

Then, add the treatment-name to your src/main/application.yml file:

split: api: key: <your split api key> treatment-name: VALIDATE_DATE
Code language: Swift (swift)

Also, when calling the getTreatment method, you should pass a string identifying the logged user as the first parameter. For our example, there’s no authentication, so it’s just ANONYMOUS_USER.

The method now starts by using the Split client to retrieve the treatment for the toggle and using its value to determine whether to check the reservation date. It then goes on to attempt creating a reservation using the service and returning the adequate error message and status code according to the result.

This code still isn’t ready to work because you haven’t defined the actual toggle on Split. That’s what you’re going to do next.

Create Your Feature Flag with Split

Go back to the Split dashboard. On the left panel, click on Splits, and then click on Create Split. You’ll be prompted for a name. Type VALIDATE_DATE and then click on Create.

You’ll then be asked to define the targeting rules for your new split. Make sure the Staging-Default environment is selected, and then click on Add Rules:

Create a feature toggle in Spring Boot with Split

Since you’ve now created a rule for your feature, Split defaults all treatments to off. That’s great because it prevents you from deploying partially complete features accidentally.

Let’s now turn the feature on to see it working in practice. Under Set The Default Rule, select on:

Set the default rule for your feature toggle treatment

After that, click on Save Changes  in the upper right corner of the page. You’ll be redirected to the changes summary page, where you’ll have the chance to review your changes one more time. If everything is correct, you can then click on Confirm.

Now, you can go back to Postman and try submitting a reservation with a date in the past. You’ll get a result like this:

{ "timestamp": "2020-07-12T02:14:12.632+00:00", "status": 400, "error": "Bad Request", "message": "The specified date is in the past.", "path": "/api/reservations" }
Code language: JSON / JSON with Comments (json)

Not Leveraging Feature Flags Is a Red Flag

Having a reliable software release life cycle is essential for any modern software development shop, and it relies on the ability to implement and deploy changes to production swiftly and consistently. This ability, which revolves around techniques like continuous integration and continuous development, is facilitated by feature toggles.

In today’s post, we’ve walked you through how to implement feature toggles in a Spring Boot app using Split. We’ve also covered the basics of feature toggling, so you understand why this technique is so powerful and useful.

Learn More about Feature Flags and Software Development with Spring Boot

As always, we’d love to have you check out our videos on YouTube, and follow us on Twitter to keep up with what’s new.