-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add sample feature flagging system to next.js template (#259)
## Changes - Add a service class for retrieving flags from evidently - Add example consuming the flags - Updated docs - tests ## Context for reviewers - This is followup / related work alongside last week's platform infra changes. ## Testing - I'd love some help testing this out against the platform infra. --------- Co-authored-by: Sawyer <[email protected]>
Showing
15 changed files
with
2,220 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
.DS_Store | ||
# Developer-specific IDE settings | ||
.vscode | ||
.env.local |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Evidently } from "@aws-sdk/client-evidently"; | ||
|
||
/** | ||
* Class for managing feature flagging via AWS Evidently. | ||
* Class method are available for use in next.js server side code. | ||
* | ||
* https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/evidently/ | ||
* | ||
*/ | ||
export class FeatureFlagManager { | ||
client: Evidently; | ||
private _project = process.env.FEATURE_FLAGS_PROJECT; | ||
|
||
constructor() { | ||
this.client = new Evidently(); | ||
} | ||
|
||
async isFeatureEnabled(featureName: string, userId?: string) { | ||
const evalRequest = { | ||
entityId: userId, | ||
feature: featureName, | ||
project: this._project, | ||
}; | ||
|
||
let featureFlagValue = false; | ||
try { | ||
const evaluation = await this.client.evaluateFeature(evalRequest); | ||
if (evaluation && evaluation.value?.boolValue !== undefined) { | ||
featureFlagValue = evaluation.value.boolValue; | ||
console.log({ | ||
message: "Made feature flag evaluation with AWS Evidently", | ||
data: { | ||
reason: evaluation.reason, | ||
userId: userId, | ||
featureName: featureName, | ||
featureFlagValue: featureFlagValue, | ||
}, | ||
}); | ||
} | ||
} catch (e) { | ||
console.error({ | ||
message: "Error retrieving feature flag variation from AWS Evidently", | ||
data: { | ||
err: e, | ||
userId: userId, | ||
featureName: featureName, | ||
}, | ||
}); | ||
} | ||
return featureFlagValue; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export class LocalFeatureFlagManager { | ||
async isFeatureEnabled(featureName: string, userId: string) { | ||
console.log("Using mock feature flag manager", { featureName, userId }); | ||
return Promise.resolve(false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { LocalFeatureFlagManager } from "../LocalFeatureFlagManager"; | ||
import type { FlagManager } from "../setup"; | ||
|
||
export const manager: FlagManager = new LocalFeatureFlagManager(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { manager } from "./setup"; | ||
|
||
export function isFeatureEnabled(feature: string, userId?: string) { | ||
return manager.isFeatureEnabled(feature, userId); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { FeatureFlagManager } from "./FeatureFlagManager"; | ||
import { LocalFeatureFlagManager } from "./LocalFeatureFlagManager"; | ||
|
||
export interface FlagManager { | ||
isFeatureEnabled(feature: string, userId?: string): Promise<boolean>; | ||
} | ||
|
||
export const manager: FlagManager = process.env.FEATURE_FLAGS_PROJECT | ||
? new FeatureFlagManager() | ||
: new LocalFeatureFlagManager(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Feature flagging | ||
|
||
- [AWS Evidently](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Evidently.html) is used for feature flagging | ||
- For more information about the decision-making behind using Evidently, [this infra ADR is available](https://github.com/navapbc/template-infra/blob/68b2db42d06198cb070b0603e63a930db346309f/docs/decisions/infra/0010-feature-flags-system-design.md) | ||
- Additional documentation of the feature flagging solution is available in [infra docs](https://github.com/navapbc/template-infra/blob/main/docs/feature-flags.md) | ||
|
||
## How it works | ||
|
||
1. `services/feature-flags/FeatureFlagManager` provides a service layer to interact with AWS Evidently endpoints. For example, class method `isFeatureEnabled` calls out to Evidently to retrieve a feature flag value we can then return to the client | ||
1. Pages can call `isFeatureEnabled` from Next.js server side code and return the feature flag value to components as props. | ||
|
||
## Local development | ||
|
||
Out-of-the-box, local calls where `FEATURE_FLAGS_PROJECT` environment variable is unset will fall back to use `LocalFeatureFlagManager` which defaults flag values to `false`. | ||
|
||
If you want to test Evidently locally, use your AWS IAM credentials. Once you set `FEATURE_FLAGS_PROJECT` and the AWS environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`) in `app/.env.local`, calls to Evidently will succeed. | ||
|
||
## Creating a new feature flag | ||
|
||
To create a new feature flag, update `/infra/[app_name]/app-config/main.tf`. More information available in infra repository [docs](https://github.com/navapbc/template-infra/blob/main/docs/feature-flags.md). | ||
|
||
## Toggling feature flags | ||
|
||
Toggle feature flags via the AWS Console GUI. More information [here](https://github.com/navapbc/template-infra/blob/main/docs/feature-flags.md#managing-feature-releases-and-partial-rollouts-via-aws-console). |