@@ -92,8 +92,8 @@ The following sample infrastructure will be used throughout this documentation:
9292 }
9393 }
9494 },
95- "feature2 ": {
96- "default": true
95+ "ten_percent_off_campaign ": {
96+ "default": false
9797 }
9898 }
9999 ContentType: 'application/json'
@@ -139,7 +139,7 @@ The following sample infrastructure will be used throughout this documentation:
139139 }
140140 }
141141 },
142- "feature2 ": {
142+ "ten_percent_off_campaign ": {
143143 "default": true
144144 }
145145 }
@@ -175,138 +175,210 @@ The following sample infrastructure will be used throughout this documentation:
175175 }
176176 ```
177177
178- ### Use feature flag store
178+ ### Evaluating a single feature flag
179+
180+ To get started, you'd need to initialize ` AppConfigStore ` and ` FeatureFlags ` . Then call ` FeatureFlags ` ` evaluate ` method to fetch, validate, and evaluate your feature.
179181
180- After you have created and configured ` AppConfigStore ` and added your feature configuraiton you can use the feature
181- flags in your code:
182+ The ` evaluate ` method supports two optional parameters:
183+
184+ * ** context** : Value to be evaluated against each rule defined for the given feature
185+ * ** default** : Sentinel value to use in case we experience any issues with our store, or feature doesn't exist
182186
183187=== "app.py"
184188
185- ```python
189+ ```python hl_lines="3 9 13 17-19"
190+ from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
191+
186192 app_config = AppConfigStore(
187193 environment="dev",
188194 application="product-catalogue",
189195 name="features"
190196 )
197+
191198 feature_flags = FeatureFlags(store=app_config)
192- ctx = {"username": "lessa", "tier": "premium", "location": "NL"}
193199
194- has_premium_features: bool = feature_flags.evaluate(name="premium_features",
195- context=ctx,
196- default=False)
200+ def lambda_handler(event, context):
201+ # Get customer's tier from incoming request
202+ ctx = { "tier": event.get("tier", "standard") }
203+
204+ # Evaluate whether customer's tier has access to premium features
205+ # based on `has_premium_features` rules
206+ has_premium_features: bool = feature_flags.evaluate(name="has_premium_features",
207+ context=ctx, default=False)
208+ if has_premium_features:
209+ # enable premium features
210+ ...
197211 ```
198212
213+ === "event.json"
214+
215+ ```json hl_lines="3"
216+ {
217+ "username": "lessa",
218+ "tier": "premium",
219+ "basked_id": "random_id"
220+ }
221+ ```
199222=== "features.json"
200223
201- ```json
202- {
203- "premium_features": {
204- "default": false,
205- "rules": {
206- "customer tier equals premium": {
207- "when_match": true,
208- "conditions": [
209- {
210- "action": "EQUALS",
211- "key": "tier",
212- "value": "premium"
213- }
214- ]
215- }
216- }
217- }
224+ ```json hl_lines="2 6 9-11"
225+ {
226+ "premium_features": {
227+ "default": false,
228+ "rules": {
229+ "customer tier equals premium": {
230+ "when_match": true,
231+ "conditions": [
232+ {
233+ "action": "EQUALS",
234+ "key": "tier",
235+ "value": "premium"
236+ }
237+ ]
238+ }
239+ }
240+ },
241+ "ten_percent_off_campaign": {
242+ "default": false
243+ }
218244 }
219245 ```
220246
221- ### Evaluating a single feature flag
247+ #### Static flags
222248
223- To fetch a single feature, setup the ` FeatureFlags ` instance and call the ` evaluate ` method.
249+ We have a static flag named ` ten_percent_off_campaign ` . Meaning, there are no conditional rules, it's either ON or OFF for all customers.
250+
251+ In this case, we could omit the ` context ` parameter and simply evaluate whether we should apply the 10% discount.
224252
225253=== "app.py"
226254
227- ```python
228- feature_flags = FeatureFlags(store=app_config)
255+ ```python hl_lines="12-13"
256+ from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
257+
258+ app_config = AppConfigStore(
259+ environment="dev",
260+ application="product-catalogue",
261+ name="features"
262+ )
263+
264+ feature_flags = FeatureFlags(store=app_config)
265+
266+ def lambda_handler(event, context):
267+ apply_discount: bool = feature_flags.evaluate(name="ten_percent_off_campaign",
268+ default=False)
229269
230- new_feature_active: bool = feature_flags.evaluate(name="new_feature",
231- default=False)
270+ if apply_discount:
271+ # apply 10% discount to product
272+ ...
232273 ```
233274
234275=== "features.json"
235276
236- ```json
237- {
238- "new_feature ": {
239- "default": true
240- }
241- }
277+ ```json hl_lines="2-3"
278+ {
279+ "ten_percent_off_campaign ": {
280+ "default": false
281+ }
282+ }
242283 ```
243284
244- In this example the feature flag is ** static** , which mean it will be evaluated without any additional context such as
245- user or location. If you want to have ** dynamic** feature flags that only works for specific user group or other contex
246- aware information you need to pass a context object and add rules to your feature configuration.
285+ ### Getting all enabled features
286+
287+ As you might have noticed, each ` evaluate ` call means an API call to the Store and the more features you have the more costly this becomes.
288+
289+ You can use ` get_enabled_features ` method for scenarios where you need a list of all enabled features according to the input context.
247290
248291=== "app.py"
249292
250- ```pyhthon
251- feature_flags = FeatureFlags(store=app_config)
252- ctx = {"username": "lessa", "tier": "premium", "location": "NL"}
293+ ```python hl_lines="17-20 23"
294+ from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver
295+ from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
253296
254- has_premium_features: bool = feature_flags.evaluate(name="premium_features",
255- context=ctx,
256- default=False
257- ```
297+ app = ApiGatewayResolver()
258298
259- === "features.json"
299+ app_config = AppConfigStore(
300+ environment="dev",
301+ application="product-catalogue",
302+ name="features"
303+ )
260304
261- ```json
262- {
263- "premium_features": {
264- "default": false,
265- "rules": {
266- "customer tier equals premium": {
267- "when_match": true,
268- "conditions": [
269- {
270- "action": "EQUALS",
271- "key": "tier",
272- "value": "premium"
273- }
274- ]
275- }
276- }
277- }
278- }
279- ```
305+ feature_flags = FeatureFlags(store=app_config)
280306
281- ### Get all enabled features
282307
283- In cases where you need to get a list of all the features that are enabled according to the input context you can
284- use ` get_enabled_features ` method:
308+ @app.get("/products")
309+ def list_products():
310+ ctx = {
311+ **app.current_event.headers,
312+ **app.current_event.json_body
313+ }
285314
286- === "app.py"
315+ # all_features is evaluated to ["geo_customer_campaign", "ten_percent_off_campaign"]
316+ all_features: list[str] = feature_flags.get_enabled_features(context=ctx)
287317
288- ```python
289- feature_flags = FeatureFlags(store=app_config)
290- ctx = {"username": "lessa", "tier": "premium", "location": "NL"}
318+ if "geo_customer_campaign" in all_features:
319+ # apply discounts based on geo
320+ ...
291321
292- all_features: list[str] = feature_flags.get_enabled_features(context=ctx)
293- # all_features is evaluated to ["feautre1", "feature2"]
322+ if "ten_percent_off_campaign" in all_features:
323+ # apply additional 10% for all customers
324+ ...
325+
326+ def lambda_handler(event, context):
327+ return app.resolve(event, context)
294328 ```
295329
330+ === "event.json"
331+
332+ ```json hl_lines="2 8"
333+ {
334+ "body": '{"username": "lessa", "tier": "premium", "basked_id": "random_id"}',
335+ "resource": "/products",
336+ "path": "/products",
337+ "httpMethod": "GET",
338+ "isBase64Encoded": false,
339+ "headers": {
340+ "CloudFront-Viewer-Country": "NL",
341+ }
342+ }
343+ ```
344+
296345=== "features.json"
297346
298- ```json hl_lines="2 6"
299- {
300- "feature1": {
301- "default": false,
302- "rules": {...}
303- },
304- "feature2": {
305- "default": false,
306- "rules": {...}
307- },
308- ...
309- }
347+ ```json hl_lines="17-18 20 27-29"
348+ {
349+ "premium_features": {
350+ "default": false,
351+ "rules": {
352+ "customer tier equals premium": {
353+ "when_match": true,
354+ "conditions": [
355+ {
356+ "action": "EQUALS",
357+ "key": "tier",
358+ "value": "premium"
359+ }
360+ ]
361+ }
362+ }
363+ },
364+ "ten_percent_off_campaign": {
365+ "default": true
366+ },
367+ "geo_customer_campaign": {
368+ "default": false,
369+ "rules": {
370+ "customer in temporary discount geo": {
371+ "when_match": true,
372+ "conditions": [
373+ {
374+ "action": "IN",
375+ "key": "CloudFront-Viewer-Country",
376+ "value": ["NL", "IE", "UK", "PL", "PT"},
377+ }
378+ ]
379+ }
380+ }
381+ }
310382 }
311383 ```
312384
0 commit comments