diff --git a/{{cookiecutter.project_slug}}/.env b/{{cookiecutter.project_slug}}/.env index 6d4b0d9..8d4992e 100644 --- a/{{cookiecutter.project_slug}}/.env +++ b/{{cookiecutter.project_slug}}/.env @@ -7,9 +7,9 @@ API_AUDIENCE=api:{{ cookiecutter.pkg_name }} DATABASE_URL=sqlite:///tmp/{{ cookiecutter.pkg_name }}.db TEST_DATABASE_URL=sqlite:///tmp/{{ cookiecutter.pkg_name }}_test.db ASYNC_ORM = 1 -# KEEP_TEST_DB=Y -# FEATURE_FLAGS_SOURCE=http://localhost:8013 +KEEP_TEST_DB=N {%- endif %} +FEATURE_FLAGS_SOURCE=flags.json WORKERS=1 ## NOTES: diff --git a/{{cookiecutter.project_slug}}/helper.py b/{{cookiecutter.project_slug}}/helper.py index b0d5c2b..20c9840 100644 --- a/{{cookiecutter.project_slug}}/helper.py +++ b/{{cookiecutter.project_slug}}/helper.py @@ -41,13 +41,13 @@ def sync2async_database_url(db_url: str) -> str: {% endif %} -def feature_gated(flag: str, default: bool = True): +def feature_gated_api(flag: str, default: bool = True): from settings import feature_client, settings def decorator_feature_flag(func): @functools.wraps(func) def sync_wrapper(*args, **kwargs): - prefix = settings.feature_prefix + prefix = settings.feature_flags_prefix enabled = feature_client.get_boolean_value(f"{prefix}.{flag}", default) if not enabled: raise HTTPException( @@ -58,7 +58,7 @@ def sync_wrapper(*args, **kwargs): @functools.wraps(func) async def async_wrapper(*args, **kwargs): - prefix = settings.feature_prefix + prefix = settings.feature_flags_prefix enabled = await feature_client.get_boolean_value_async( f"{prefix}.{flag}", True ) diff --git a/{{cookiecutter.project_slug}}/settings.py b/{{cookiecutter.project_slug}}/settings.py index fc0d661..a5b3d47 100644 --- a/{{cookiecutter.project_slug}}/settings.py +++ b/{{cookiecutter.project_slug}}/settings.py @@ -30,12 +30,12 @@ class AppSettings(BaseSettings): {% endif %} # for OpenFeature - feature_flags_source: str = "flags.json" - feature_prefix: str = "" + feature_flags_source: str = "http://localhost:8013" + feature_flags_prefix: str = "" settings = AppSettings() -settings.feature_prefix = settings.feature_prefix or settings.app_name +settings.feature_flags_prefix = settings.feature_flags_prefix or settings.app_name {% if "sqlmodel" in cookiecutter.extra_packages %} if settings.async_orm and not settings.database_url_async: diff --git a/{{cookiecutter.project_slug}}/tests/test_{{ cookiecutter.pkg_name }}.py b/{{cookiecutter.project_slug}}/tests/test_{{ cookiecutter.pkg_name }}.py index 752c9fe..95ba079 100644 --- a/{{cookiecutter.project_slug}}/tests/test_{{ cookiecutter.pkg_name }}.py +++ b/{{cookiecutter.project_slug}}/tests/test_{{ cookiecutter.pkg_name }}.py @@ -25,7 +25,9 @@ async def test_secret_authenticated(client): async def test_get_something_useful(client): response = client.get("/api/useful") - # feature disabled by feature flag will return 403 + # feature flag defaults to true. + # flags.json will return false, if it works properly + # the test will be successful only if flagd is return the correct data. assert response.status_code == 403 {% endif %} diff --git a/{{cookiecutter.project_slug}}/{{ cookiecutter.pkg_name }}/api.py b/{{cookiecutter.project_slug}}/{{ cookiecutter.pkg_name }}/api.py index 03da472..bf8e3ea 100644 --- a/{{cookiecutter.project_slug}}/{{ cookiecutter.pkg_name }}/api.py +++ b/{{cookiecutter.project_slug}}/{{ cookiecutter.pkg_name }}/api.py @@ -3,7 +3,7 @@ from fastapi import APIRouter, Depends, HTTPException -from helper import feature_gated +from helper import feature_gated_api from security import get_jwt_verifier {%- if "sqlmodel" in cookiecutter.extra_packages %} @@ -57,6 +57,6 @@ async def read_user_async( @router.get("/useful") -@feature_gated("useful_svc") # this must be after the @router +@feature_gated_api("useful_svc") # this must be after the @router async def get_something_useful(): return {"info": "Isn't this useful?!"}