forked from aws-powertools/powertools-lambda-python
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(docs): Extract feature flag code examples
Changes: - Extract code examples - Run isort, black - Correct line highlights - Add make task Related to: - aws-powertools#1064
- Loading branch information
1 parent
b577366
commit 555dd59
Showing
13 changed files
with
346 additions
and
323 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
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,25 @@ | ||
import jmespath | ||
from botocore.config import Config | ||
|
||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore | ||
|
||
boto_config = Config(read_timeout=10, retries={"total_max_attempts": 2}) | ||
|
||
# Custom JMESPath functions | ||
class CustomFunctions(jmespath.functions.Functions): | ||
@jmespath.functions.signature({"types": ["string"]}) | ||
def _func_special_decoder(self, s): | ||
return my_custom_decoder_logic(s) | ||
|
||
|
||
custom_jmespath_options = {"custom_functions": CustomFunctions()} | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="configuration", | ||
max_age=120, | ||
envelope="features", | ||
sdk_config=boto_config, | ||
jmespath_options=custom_jmespath_options, | ||
) |
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,8 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="features", | ||
max_age=300, | ||
) |
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,58 @@ | ||
import json | ||
|
||
import aws_cdk.aws_appconfig as appconfig | ||
from aws_cdk import core | ||
|
||
|
||
class SampleFeatureFlagStore(core.Construct): | ||
def __init__(self, scope: core.Construct, id_: str) -> None: | ||
super().__init__(scope, id_) | ||
|
||
features_config = { | ||
"premium_features": { | ||
"default": False, | ||
"rules": { | ||
"customer tier equals premium": { | ||
"when_match": True, | ||
"conditions": [{"action": "EQUALS", "key": "tier", "value": "premium"}], | ||
} | ||
}, | ||
}, | ||
"ten_percent_off_campaign": {"default": True}, | ||
} | ||
|
||
self.config_app = appconfig.CfnApplication( | ||
self, | ||
id="app", | ||
name="product-catalogue", | ||
) | ||
self.config_env = appconfig.CfnEnvironment( | ||
self, | ||
id="env", | ||
application_id=self.config_app.ref, | ||
name="dev-env", | ||
) | ||
self.config_profile = appconfig.CfnConfigurationProfile( | ||
self, | ||
id="profile", | ||
application_id=self.config_app.ref, | ||
location_uri="hosted", | ||
name="features", | ||
) | ||
self.hosted_cfg_version = appconfig.CfnHostedConfigurationVersion( | ||
self, | ||
"version", | ||
application_id=self.config_app.ref, | ||
configuration_profile_id=self.config_profile.ref, | ||
content=json.dumps(features_config), | ||
content_type="application/json", | ||
) | ||
self.app_config_deployment = appconfig.CfnDeployment( | ||
self, | ||
id="deploy", | ||
application_id=self.config_app.ref, | ||
configuration_profile_id=self.config_profile.ref, | ||
configuration_version=self.hosted_cfg_version.ref, | ||
deployment_strategy_id="AppConfig.AllAtOnce", | ||
environment_id=self.config_env.ref, | ||
) |
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,8 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="configuration", | ||
envelope="feature_flags", | ||
) |
34 changes: 34 additions & 0 deletions
34
docs/examples/utilities/feature_flags/get_enabled_features.py
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,34 @@ | ||
from aws_lambda_powertools.event_handler import APIGatewayRestResolver | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags | ||
|
||
app = APIGatewayRestResolver() | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="features", | ||
) | ||
feature_flags = FeatureFlags(store=app_config) | ||
|
||
|
||
@app.get("/products") | ||
def list_products(): | ||
ctx = { | ||
**app.current_event.headers, | ||
**app.current_event.json_body, | ||
} | ||
|
||
# all_features is evaluated to ["geo_customer_campaign", "ten_percent_off_campaign"] | ||
all_features: list[str] = feature_flags.get_enabled_features(context=ctx) | ||
|
||
if "geo_customer_campaign" in all_features: | ||
# apply discounts based on geo | ||
... | ||
|
||
if "ten_percent_off_campaign" in all_features: | ||
# apply additional 10% for all customers | ||
... | ||
|
||
|
||
def lambda_handler(event, context): | ||
return app.resolve(event, context) |
12 changes: 12 additions & 0 deletions
12
docs/examples/utilities/feature_flags/get_raw_configuration.py
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,12 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="configuration", | ||
envelope="feature_flags", | ||
) | ||
|
||
feature_flags = FeatureFlags(store=app_config) | ||
|
||
config = app_config.get_raw_configuration |
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 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="features", | ||
) | ||
|
||
feature_flags = FeatureFlags(store=app_config) | ||
|
||
|
||
def lambda_handler(event, context): | ||
# Get customer's tier from incoming request | ||
ctx = {"tier": event.get("tier", "standard")} | ||
|
||
# Evaluate `has_premium_features` base don customer's tier | ||
premium_features: list[str] = feature_flags.evaluate( | ||
name="premium_features", | ||
context=ctx, | ||
default=False, | ||
) | ||
for feature in premium_features: | ||
# enable premium features | ||
... |
25 changes: 25 additions & 0 deletions
25
docs/examples/utilities/feature_flags/single_feature_flag.py
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,25 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="features", | ||
) | ||
|
||
feature_flags = FeatureFlags(store=app_config) | ||
|
||
|
||
def lambda_handler(event, context): | ||
# Get customer's tier from incoming request | ||
ctx = {"tier": event.get("tier", "standard")} | ||
|
||
# Evaluate whether customer's tier has access to premium features | ||
# based on `has_premium_features` rules | ||
has_premium_features: bool = feature_flags.evaluate( | ||
name="premium_features", | ||
context=ctx, | ||
default=False, | ||
) | ||
if has_premium_features: | ||
# enable premium features | ||
... |
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,20 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags | ||
|
||
app_config = AppConfigStore( | ||
environment="dev", | ||
application="product-catalogue", | ||
name="features", | ||
) | ||
|
||
feature_flags = FeatureFlags(store=app_config) | ||
|
||
|
||
def lambda_handler(event, context): | ||
apply_discount: bool = feature_flags.evaluate( | ||
name="ten_percent_off_campaign", | ||
default=False, | ||
) | ||
|
||
if apply_discount: | ||
# apply 10% discount to product | ||
... |
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,60 @@ | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
Description: Lambda Powertools Feature flags sample template | ||
Resources: | ||
FeatureStoreApp: | ||
Type: AWS::AppConfig::Application | ||
Properties: | ||
Description: "AppConfig Application for feature toggles" | ||
Name: product-catalogue | ||
|
||
FeatureStoreDevEnv: | ||
Type: AWS::AppConfig::Environment | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
Description: "Development Environment for the App Config Store" | ||
Name: dev | ||
|
||
FeatureStoreConfigProfile: | ||
Type: AWS::AppConfig::ConfigurationProfile | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
Name: features | ||
LocationUri: "hosted" | ||
|
||
HostedConfigVersion: | ||
Type: AWS::AppConfig::HostedConfigurationVersion | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
ConfigurationProfileId: !Ref FeatureStoreConfigProfile | ||
Description: 'A sample hosted configuration version' | ||
Content: | | ||
{ | ||
"premium_features": { | ||
"default": false, | ||
"rules": { | ||
"customer tier equals premium": { | ||
"when_match": true, | ||
"conditions": [ | ||
{ | ||
"action": "EQUALS", | ||
"key": "tier", | ||
"value": "premium" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"ten_percent_off_campaign": { | ||
"default": false | ||
} | ||
} | ||
ContentType: 'application/json' | ||
|
||
ConfigDeployment: | ||
Type: AWS::AppConfig::Deployment | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
ConfigurationProfileId: !Ref FeatureStoreConfigProfile | ||
ConfigurationVersion: !Ref HostedConfigVersion | ||
DeploymentStrategyId: "AppConfig.AllAtOnce" | ||
EnvironmentId: !Ref FeatureStoreDevEnv |
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,48 @@ | ||
from aws_lambda_powertools.utilities.feature_flags import AppConfigStore, FeatureFlags, RuleAction | ||
|
||
|
||
def init_feature_flags(mocker, mock_schema, envelope="") -> FeatureFlags: | ||
"""Mock AppConfig Store get_configuration method to use mock schema instead""" | ||
|
||
method_to_mock = "aws_lambda_powertools.utilities.feature_flags.AppConfigStore.get_configuration" | ||
mocked_get_conf = mocker.patch(method_to_mock) | ||
mocked_get_conf.return_value = mock_schema | ||
|
||
app_conf_store = AppConfigStore( | ||
environment="test_env", | ||
application="test_app", | ||
name="test_conf_name", | ||
envelope=envelope, | ||
) | ||
|
||
return FeatureFlags(store=app_conf_store) | ||
|
||
|
||
def test_flags_condition_match(mocker): | ||
# GIVEN | ||
expected_value = True | ||
mocked_app_config_schema = { | ||
"my_feature": { | ||
"default": expected_value, | ||
"rules": { | ||
"tenant id equals 12345": { | ||
"when_match": True, | ||
"conditions": [ | ||
{ | ||
"action": RuleAction.EQUALS.value, | ||
"key": "tenant_id", | ||
"value": "12345", | ||
} | ||
], | ||
} | ||
}, | ||
} | ||
} | ||
|
||
# WHEN | ||
ctx = {"tenant_id": "12345", "username": "a"} | ||
feature_flags = init_feature_flags(mocker=mocker, mock_schema=mocked_app_config_schema) | ||
flag = feature_flags.evaluate(name="my_feature", context=ctx, default=False) | ||
|
||
# THEN | ||
assert flag == expected_value |
Oops, something went wrong.