Modifying Application Behavior with Go Lambda Functions and AWS AppConfig Feature Flags
Posted July 5, 2022 by Trevor Roberts Jr ‐ 7 min read
The Obi-Wan Kenobi series' depiction of the conflict between light and dark reminded me of a similar struggle faced by my favorite video game character: Cecil (Final Fantasy IV). I used AWS AppConfig Feature Flags to dynamically generate an information page about Cecil based on his decision...
Introduction
Developers can use AWS AppConfig for a simplified implementation of feature flags to alter an application’s behavior. My sample application displays information about a fictional character named Cecil. The displayed data varies according to Cecil's allegiance to the dark or to the light. If you don’t use feature flags today to modify your application behavior, read on to see how this feature may fit in with your upcoming projects!
What is AWS AppConfig?
AWS AppConfig is a capability built into AWS Systems Manager that allows developers to dynamically alter application functionality. In March 2022, the AWS AppConfig team made the Feature Flags capability generally available. This release added more functionality including setting constraints on the data types and acceptable values and rolling back feature flag updates based on CloudWatch alarms.
Why not use other services (ex: Amazon DynamoDB, Amazon S3, or Amazon ElastiCache)?
It is possible to use another service to manage your feature flag data. However, the advanced capabilties I mentioned earlier (i.e. feature flag validation and rollback) would need to be built into your application. When using AWS AppConfig, you can offload that complexity to AWS and focus on your core application code. To read more about AWS AppConfig's use cases, check out the documentation.
My Application
I created a simple web application that displays different character designs for Cecil depending on whether he remains a Dark Knight or becomes a Paladin.
My application's frontend consists of an HTML page with an empty div tag that will be populated with code returned by a JavaScript query (credit to the AppConfig Feature Flags Workshop for the idea.)
The empty div tag:
<div id="displayCecil">
</div>
The JavaScript code to update the div content based on the Lambda function return data:
fetch('https://1234567890987654321abccba.lambda-url.us-east-1.on.aws/')
.then(response => response.text())
.then((data) => {
document.getElementById("displayCecil").innerHTML = data;
console.log(data);
});
The JavaScript code is using my Lambda function's URL to obtain the information about Cecil to display in the browser. The Lambda function changes what data it returns based on the current setting of the AppConfig feature flag. I'll step through the lines of code relevant to AppConfig since I've done a walkthrough of how to write a Lambda function in Go in a previous blog post:
First, I initialize a client for the AppConfig service specific to retrieving data:
// Create a AppConfigData client from the AWS Session.
svc := appconfigdata.New(mySession)
I obtain a token that is required to make a query of the AppConfig service. I must specify my AppConfig application, configuration profile, and environment identifiers that I created in advance in the AppConfig service. This ensures my application is reading the correct feature flag data.
token, err := svc.StartConfigurationSession(&appconfigdata.StartConfigurationSessionInput{
// The ApplicationIdentifier for the application that depends on the feature flag.
ApplicationIdentifier: jsii.String(ApplicationIdentifier),
// The configuration profile ID or the configuration profile name.
ConfigurationProfileIdentifier: jsii.String(ConfigurationProfileIdentifier),
// The AppConfig environment ID (ex: dev, beta, prod, etc.).
EnvironmentIdentifier: jsii.String(EnvironmentIdentifier),
})
I then use the token to make a GetLatestConfiguration API call to the AppConfig service. This returns whatever is the latest value that the feature flag is set to.
result, err := svc.GetLatestConfiguration(&appconfigdata.GetLatestConfigurationInput{
ConfigurationToken: jsii.String(*token.InitialConfigurationToken),
})
Finally, I create structs for the JSON data returned by the AppConfig service, and I use the feature flag data (featureFlagResults.Allegiance.Choice) to determine which HTML code should be returned by the Lambda function invocation.
type featureflagdata struct {
Choice string
Enabled bool
}
type featureflag struct {
Allegiance featureflagdata
}
var featureFlagResults featureflag
json.Unmarshal(result.Configuration, &featureFlagResults)
CecilsChoice := featureFlagResults.Allegiance.Choice
if CecilsChoice == "paladin" {
return fmt.Sprintf(htmlPaladinOutput), nil
}
return fmt.Sprintf(htmlDarkKnightOutput), nil
FYI, the complete Lambda source code can be found on GitHub.
My application's feature flag is initially set to darkknight. I then update my feature flag as follows in the AWS AppConfig console (you can make your update via API and CLI as well):
I click on my AppConfig Application (blogAppConfigGo)
I click on my feature flag (whichSide)
I click on edit.
Notice the constraint textbox which lists the acceptable values for the feature flags. I update to paladin and click Confirm
I click on Save new version (Yes! your feature flags are versioned for simplified rollback)
I click on Start Deployment
I select my environment (prod...why not?) and select a Deployment strategy that dictates how the feature flag should be rolled out to your environment. I click Start deployment
I observe the deployment progress
My deployment is complete, and the application is adjusted as shown in Figure 02 earlier in the blog
AWS AppConfig and Go Lambda Functions
The AppConfig service features a simple integration using Lambda Layers for multiple runtimes. The Go runtime isn’t on the supported list today. However, you can try out the Lambda Layer capability by running through the AWS AppConfig Feature Flags Workshop. If you are a Go developer and like the Lambda Layers approach, please be sure to let your AWS account team know!
What's Next?
When using this service, make sure to lockdown IAM permissions for AppConfig configuration profile updates. It is advisable to use automation tooling to update your feature flag to reduce human error. One more feature to be aware of is that you can trigger feature flag update rollbacks in response to CloudWatch Alarms. In my next blog post, I'll share how I automated the creation of my application's AWS AppConfig feature flag with Pulumi.
If you found this article useful, let me know on Twitter!