Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions {{cookiecutter.project_slug}}/.env
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions {{cookiecutter.project_slug}}/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
)
Expand Down
6 changes: 3 additions & 3 deletions {{cookiecutter.project_slug}}/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link

Copilot AI May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for feature_flags_source in settings.py now differs from the value set in the .env file (which is 'flags.json'). Consider aligning these values to avoid potential configuration inconsistencies.

Suggested change
feature_flags_source: str = "http://localhost:8013"
feature_flags_source: str = "flags.json"

Copilot uses AI. Check for mistakes.
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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment on lines +28 to +30
Copy link

Copilot AI May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The updated test comments in the feature flag test are ambiguous compared to the expected status code (403). Update the comments to clearly explain the expected behavior and conditions under which the feature is disabled.

Suggested change
# 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.
# The feature flag for this endpoint defaults to enabled (true).
# If the feature flag is disabled (false) in flags.json, the endpoint should return a 403 status code.
# This test verifies that the system correctly enforces the feature flag's state as defined in flags.json.

Copilot uses AI. Check for mistakes.
assert response.status_code == 403

{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
Expand Down Expand Up @@ -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?!"}
Loading