@@ -92,8 +92,8 @@ The following sample infrastructure will be used throughout this documentation:
92
92
}
93
93
}
94
94
},
95
- "feature2 ": {
96
- "default": true
95
+ "ten_percent_off_campaign ": {
96
+ "default": false
97
97
}
98
98
}
99
99
ContentType: 'application/json'
@@ -139,7 +139,7 @@ The following sample infrastructure will be used throughout this documentation:
139
139
}
140
140
}
141
141
},
142
- "feature2 ": {
142
+ "ten_percent_off_campaign ": {
143
143
"default": true
144
144
}
145
145
}
@@ -175,138 +175,210 @@ The following sample infrastructure will be used throughout this documentation:
175
175
}
176
176
```
177
177
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.
179
181
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
182
186
183
187
=== "app.py"
184
188
185
- ```python
189
+ ```python hl_lines="3 9 13 17-19"
190
+ from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
191
+
186
192
app_config = AppConfigStore(
187
193
environment="dev",
188
194
application="product-catalogue",
189
195
name="features"
190
196
)
197
+
191
198
feature_flags = FeatureFlags(store=app_config)
192
- ctx = {"username": "lessa", "tier": "premium", "location": "NL"}
193
199
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
+ ...
197
211
```
198
212
213
+ === "event.json"
214
+
215
+ ```json hl_lines="3"
216
+ {
217
+ "username": "lessa",
218
+ "tier": "premium",
219
+ "basked_id": "random_id"
220
+ }
221
+ ```
199
222
=== "features.json"
200
223
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
+ }
218
244
}
219
245
```
220
246
221
- ### Evaluating a single feature flag
247
+ #### Static flags
222
248
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.
224
252
225
253
=== "app.py"
226
254
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)
229
269
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
+ ...
232
273
```
233
274
234
275
=== "features.json"
235
276
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
+ }
242
283
```
243
284
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.
247
290
248
291
=== "app.py"
249
292
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
253
296
254
- has_premium_features: bool = feature_flags.evaluate(name="premium_features",
255
- context=ctx,
256
- default=False
257
- ```
297
+ app = ApiGatewayResolver()
258
298
259
- === "features.json"
299
+ app_config = AppConfigStore(
300
+ environment="dev",
301
+ application="product-catalogue",
302
+ name="features"
303
+ )
260
304
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)
280
306
281
- ### Get all enabled features
282
307
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
+ }
285
314
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)
287
317
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
+ ...
291
321
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)
294
328
```
295
329
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
+
296
345
=== "features.json"
297
346
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
+ }
310
382
}
311
383
```
312
384
0 commit comments