Java

Using Togglz in a Kotlin Spring Boot Project – Part 1

Full Source Code

If you aren’t using Feature Flags in your software project yet, you should start right away. It’s the key to unlocking Continuous Deployment in production, as well your best friend in managing release risks. I won’t belabor the point here, but checkout the excellent guides from Atlassian and LaunchDarkly. The good news is that no matter what stack you are working in, there’s probably an existing framework for managing flags.

One of my favorite implementations for the JVM is Togglz. Let’s walk through the setup of Togglz in a Sprint Boot + Kotlin project.

I’m using Intellij Idea for access to it’s easy Spring Boot starter. We’ll create a project with Spring Web dependencies.

For this example, we’ll just build a RESTful service, starting with a really simple controller.

package com.example.springkotlintogglz.controllers

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class HomeController() {
    @GetMapping("/")
    fun index() = "Hello, World!"
}

Run your app, and you should see it working, like so:

Great, lets add some feature toggles. Start by adding the following lines to the dependencies section of you build.gradle.kts

    implementation("org.togglz:togglz-spring-boot-starter:3.1.2")
    implementation("org.togglz:togglz-kotlin:2.8.0")

We’ll also need a Kotlin configuration file – TogglzConfiguration.kt We’ll add a single feature flag, controlled through a code-level enum. I know, the point of feature flags is to allow changes without a code release, we’ll get to that later, for now, we’ll code the flag into the enum to get a feel for the code.

package com.example.springkotlintogglz

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.togglz.core.context.FeatureContext
import org.togglz.core.context.StaticFeatureManagerProvider
import org.togglz.core.manager.FeatureManager
import org.togglz.core.manager.FeatureManagerBuilder
import org.togglz.core.repository.StateRepository
import org.togglz.core.repository.file.FileBasedStateRepository
import org.togglz.core.spi.FeatureProvider
import org.togglz.core.user.NoOpUserProvider
import org.togglz.core.user.UserProvider
import org.togglz.kotlin.EnumClassFeatureProvider
import java.io.File

@Configuration
class TogglzConfiguration {

    @Bean
    fun featureProvider() = EnumClassFeatureProvider(KotlinTestFeatures::class.java)

    @Bean
    fun stateRepository() = FileBasedStateRepository(File("/tmp/togglz-features.properties"))

    @Bean
    fun userProvider() = NoOpUserProvider()

    @Bean
    @Primary
    fun myFeatureManager(stateRepository: StateRepository,
                         userProvider: UserProvider,
                         featureProvider: FeatureProvider): FeatureManager {

        val featureManager = FeatureManagerBuilder()
                .featureProvider(featureProvider)
                .stateRepository(stateRepository)
                .userProvider(userProvider)
                .build()

        StaticFeatureManagerProvider.setFeatureManager(featureManager)
        return featureManager
    }
}

enum class KotlinTestFeatures {
    HELLO_WORLD;

    fun isActive(): Boolean {
        return FeatureContext.getFeatureManager().isActive { name }
    }
}

Now that we have the supporting code in place, we can modify our controller to use the flag. Update your HomeController.kt to alter the behavior based on the flag state.

package com.example.springkotlintogglz.controllers

import com.example.springkotlintogglz.KotlinTestFeatures
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class HomeController() {
    @GetMapping("/")
    fun index(): String {
        if (KotlinTestFeatures.HELLO_WORLD.isActive()) {
            return "Hello, World!"
        } else {
            return "Not Implemented"
        }
    }
}

Run your application, and you should get a “Not Implemented” output.

To confirm that these can actually “toggle”, lets turn this flag on. Update your TogglzConfiguration.kt to match the code below. In this simple example we are employing the @EnabledByDefault annotation.

enum class KotlinTestFeatures {
    @EnabledByDefault HELLO_WORLD;

    fun isActive(): Boolean {
        return FeatureContext.getFeatureManager().isActive { name }
    }
}

There you have it, the simplest setup to show that the Togglz library is working for us. Given that everything is hard coded, the value is limited, but in Part 2, we’ll make this production quality by introducing a data store & an admin interface.

Full Source Code


Leave a Reply

Your email address will not be published. Required fields are marked *