Modifying Application Behavior with Go Lambda Functions and AWS AppConfig Feature Flags
Tags: go, aws, lambda
Published: 2023-04-07 13:08:45

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](https://aws.amazon.com/systems-manager/faq/) that allows developers to dynamically alter application functionality. In March 2022, the AWS AppConfig team made the [Feature Flags](https://aws.amazon.com/about-aws/whats-new/2022/03/aws-appconfig-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](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html).

## 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.

![Figure 01: Cecil Remains a Dark Knight](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3qcikd1fwvc490lddioq.png)
Figure 01: Cecil Remains a Dark Knight

![Figure 02: Cecil Becomes a Paladin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99fs2fkn49zpjws047fu.png)
Figure 02: Cecil 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](https://catalog.us-east-1.prod.workshops.aws/workshops/2ee2fc71-0618-479c-86dd-1d5fb168eb20/en-US) for the idea.)

The empty div tag:
```html
	<div id="displayCecil">

    </div>
```
The JavaScript code to update the div content based on the Lambda function return data:
```javascript
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](@/blog/cloudfront-cache-invalidation-go.md):

First, I initialize a client for the AppConfig service specific to retrieving data:

```go
	// 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.

```go
	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.

```go
	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.

```go
    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](https://github.com/trevorrobertsjr/appconfig-blog-go/blob/main/lambda/Lambda.go).

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)

![Figure 03: AWS AppConfig Service Home Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xt8323cmexvbhpi9cec0.png)
Figure 03: AWS AppConfig Service Home Page

I click on my feature flag (whichSide)

![Figure 04: AppConfig Application Details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x74pazsnolyi1z93modt.png)
Figure 04: AppConfig Application Details

I click on edit.

![Figure 05: Feature Flag Details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mtp5akcpcg08rsyd6k2j.png)
Figure 05: Feature Flag Details

Notice the constraint textbox which lists the acceptable values for the feature flags. I update to **paladin** and click **Confirm**

![Figure 06: Updating the Feature Flag](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23ux97cajil3t1vwblow.png)
Figure 06: Updating the Feature Flag

I click on **Save new version** (Yes! your feature flags are versioned for simplified rollback)

![Figure 07: Save a New Feature Flag Version](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eppoyokj6hkszoyw24by.png)
Figure 07: Save a New Feature Flag Version

I click on **Start Deployment**

![Figure 08: Start the Feature Flag Deployment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6ea54dqiz8gfgmyw6qp.png)
Figure 08: Start the Feature Flag 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**

![Figure 09: Confirm the Deployment Parameters](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/684ls8wykad164d5elas.png)
Figure 09: Confirm the Deployment Parameters

I observe the deployment progress

![Figure 10: Feature Flag Deployment Progress](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo43phh7cyg3t8djfjav.png)
Figure 10: Feature Flag Deployment Progress

My deployment is complete, and the application is adjusted as shown in **Figure 02** earlier in the blog

![Figure 11: Feature Flag Deployment Complete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9nsykipvckk7ocs9z1e.png)
Figure 11: Feature Flag Deployment Complete



## AWS AppConfig and Go Lambda Functions
The AppConfig service features a simple integration using Lambda Layers for [multiple runtimes](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html#appconfig-integratio-lambda-extensions-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](https://catalog.us-east-1.prod.workshops.aws/workshops/2ee2fc71-0618-479c-86dd-1d5fb168eb20/en-US). 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](https://twitter.com/trevorrobertsjr)!