fastapi.py
1 """ 2 FastAPI dependency helpers for feature flag gating. 3 4 These helpers wrap the OpenFeature client for use as FastAPI ``Depends`` 5 injectors. They are framework-specific and live here rather than in 6 ``core.py`` to keep the core module framework-agnostic. 7 8 Usage:: 9 10 from solace_agent_mesh.common.features.fastapi import ( 11 require_feature, 12 get_feature_value, 13 ) 14 15 # Hard-gate an entire endpoint — returns 404 when flag is off: 16 @router.get("/my-endpoint") 17 async def my_endpoint(_: None = Depends(require_feature("my_flag"))): 18 ... 19 20 # Inject the flag value for soft behaviour changes: 21 @router.get("/my-endpoint") 22 async def my_endpoint(flag: bool = Depends(get_feature_value("my_flag"))): 23 if flag: 24 ... 25 """ 26 27 from __future__ import annotations 28 29 from collections.abc import Callable 30 31 from fastapi import HTTPException, status 32 from openfeature import api as openfeature_api 33 34 35 def require_feature(key: str) -> Callable: 36 """ 37 FastAPI dependency factory that hard-gates an endpoint on a feature flag. 38 39 Raises HTTP 404 when the flag is disabled so that the endpoint appears 40 non-existent to callers. Use when the entire endpoint should be 41 unavailable while the flag is off. 42 43 For soft behaviour changes based on a flag, use :func:`get_feature_value`. 44 """ 45 def _check() -> None: 46 if not openfeature_api.get_client().get_boolean_value(key, False): 47 raise HTTPException( 48 status_code=status.HTTP_404_NOT_FOUND, 49 detail=f"Feature '{key}' is not enabled.", 50 ) 51 return _check 52 53 54 def get_feature_value(key: str) -> Callable: 55 """ 56 FastAPI dependency factory that injects the current boolean value of a 57 feature flag into an endpoint without raising on disabled. 58 59 Use when the endpoint should remain accessible but needs to vary its 60 behaviour based on whether the flag is on or off. 61 """ 62 def _resolve() -> bool: 63 return openfeature_api.get_client().get_boolean_value(key, False) 64 return _resolve