Skip to content

Conversation

@gagantrivedi
Copy link
Member

@gagantrivedi gagantrivedi commented Nov 19, 2025

Thanks for submitting a PR! Please check the boxes below:

  • I have added information to docs/ if required so people know about the feature!
  • I have filled in the "Changes" section below?
  • I have filled in the "How did you test this code" section below?
  • I have used a Conventional Commit title for this Pull Request

Changes

Adds two new experimental endpoints under /api/experiments/:

How did you test this code?

Unit tests

matthewelwell and others added 2 commits October 29, 2025 10:23
Adds two new experimental endpoints under /api/experiments/:
- update-flag-v1: Update single feature state (environment default or segment override)
- update-flag-v2: Update multiple feature states in a single request (environment default + segment overrides)
@vercel
Copy link

vercel bot commented Nov 19, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs Ignored Ignored Preview Dec 5, 2025 7:21am
flagsmith-frontend-preview Ignored Ignored Preview Dec 5, 2025 7:21am
flagsmith-frontend-staging Ignored Ignored Preview Dec 5, 2025 7:21am

@gagantrivedi gagantrivedi changed the title Feat/experimental flag update endpoints feat(api): add experimental feature flag update endpoints Nov 19, 2025
@github-actions github-actions bot added the api Issue related to the REST API label Nov 19, 2025
@github-actions github-actions bot added the feature New feature or request label Nov 19, 2025
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Nov 26, 2025
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Nov 26, 2025
@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.05%. Comparing base (bebb47b) to head (3704c9c).
⚠️ Report is 36 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6305      +/-   ##
==========================================
+ Coverage   98.02%   98.05%   +0.03%     
==========================================
  Files        1280     1289       +9     
  Lines       45406    46147     +741     
==========================================
+ Hits        44508    45249     +741     
  Misses        898      898              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Parameterize test_update_flag_by_name for all value types (integer, string, boolean)
- Remove unsupported float type from serializer (model doesn't support it)
- Add test_serializers.py with unit tests for edge cases
- Add test for duplicate segment_id validation
- Add tests for updating existing segment overrides with priority
- Add unit tests for boolean string conversion and replica path
- Refactor _update_flag_for_versioning_v2 to separate segment vs environment
  default cases for cleaner code and full coverage
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Nov 28, 2025
Replace SDK endpoint calls with direct database verification using
get_environment_flags_list. This keeps the tests as proper unit tests
rather than integration tests.

- Remove sdk_client and sdk_client_factory fixtures
- Remove get_identity_feature_state_from_sdk helper function
- Remove Identity, Condition, SegmentRule imports and usage
- Simplify segment override tests to verify database state directly
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Nov 28, 2025
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Nov 28, 2025
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Nov 28, 2025
@gagantrivedi gagantrivedi force-pushed the feat/experimental-flag-update-endpoints branch from f280c7f to b987697 Compare November 28, 2025 13:29
@gagantrivedi gagantrivedi force-pushed the feat/experimental-flag-update-endpoints branch from e998a78 to 56443a0 Compare December 4, 2025 08:21
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Dec 4, 2025
…rides

Creating a FeatureSegment with a priority value doesn't trigger reordering
of existing segments. Use .to() after creation to properly reorder.

Fixes both V1 and V2 endpoints.
@gagantrivedi gagantrivedi force-pushed the feat/experimental-flag-update-endpoints branch from 56443a0 to 8d43e11 Compare December 4, 2025 11:31
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Dec 4, 2025
…ride

Prevents cross-project segment references and provides clear error
messages for non-existent segments.
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Dec 4, 2025
Copy link
Contributor

@emyller emyller left a comment

Choose a reason for hiding this comment

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

The experiment looks solid, despite the complexity brought by the 2x2 grid experiment x versioning version. Few suggestions.


def update_traits(
self,
# TODO: this typing isn't true as it also supports regular dicts like {"trait_key": "foo", "trait_value": "bar"}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have an issue to cover this?

Copy link
Member Author

Choose a reason for hiding this comment

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

I am not sure why it's part of this pr

Copy link
Member Author

Choose a reason for hiding this comment

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

here: #6371

Comment on lines +72 to +83
if value_type == "integer":
try:
int(string_val)
except ValueError:
raise serializers.ValidationError(
f"'{string_val}' is not a valid integer"
)
elif value_type == "boolean":
if string_val.lower() not in ("true", "false"):
raise serializers.ValidationError(
f"'{string_val}' is not a valid boolean (use 'true' or 'false')"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have this logic abstracted? It is repeated but raising distinct exceptions, e.g. ValueError there, and ValidationError here.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is intentional defense in depth. The serializer validates at the API boundary and returns 400 with user-friendly errors. The model validates at the data layer to prevent corruption if set_value() is called directly (e.g.,
from management commands, tasks, or other code paths). Different layers appropriately raise different exceptions: ValidationError for API responses, ValueError for programmatic misuse.

)
serializer.is_valid()

with pytest.raises(Exception) as exc_info:
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to narrow down this exception type?

Copy link
Contributor

Choose a reason for hiding this comment

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

Missing Given/When/Then markers.

)


def update_flag(
Copy link
Contributor

Choose a reason for hiding this comment

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

These functions perform multiple database writes without @transaction.atomic. Can we wrap them?

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't have any early exits or conditional paths here that could leave things in a bad state - it's just a straight line of create → update → save. If any step fails, it raises and stops.

Also, if something does fail midway, we'd actually want to know about it. A 500 surfacing is useful signal - silently rolling back could hide bugs we should be investigating.

Worth noting that FeatureState is one of our hottest tables, so holding transaction locks longer than needed would hurt concurrent traffic.

Happy to add one if there's a specific consistency case I'm missing though!


updated_segments = []
for override in change_set.segment_overrides:
segment_states = get_environment_flags_dict(
Copy link
Contributor

Choose a reason for hiding this comment

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

get_environment_flags_dict is called once per segment override. Can we batch this into a single query?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd prefer to do that once this API is out of the experimentation stage

feature_name=feature.name,
additional_filters=Q(feature_segment__isnull=True, identity_id__isnull=True),
)
assert len(env_default_states) == 1
Copy link
Contributor

Choose a reason for hiding this comment

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

assert provides no message when it fails. Can we raise an explicit exception instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't expect it to fail. The assert is only included to improve readability and document the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have a test for concurrent modifications? This is relevant since atomicity is not implemented yet (see other thread).

Copy link
Member Author

Choose a reason for hiding this comment

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

That’s a fair point regarding concurrency. However, I’m a bit hesitant to add a specific test for it right now. In my experience, tests requiring thread orchestration to hit precise race windows tend to be quite flaky and hard to maintain.

Also, looking at the logic, I’m not sure a test would give us much new signal. Since we aren't implementing strict locking:

V2: Relies on versioning (last publisher wins).

V1: Defaults to 'last write wins.'

Essentially, the test would just confirm that the last request overwrites the previous one, which is the expected behavior rather than a defect we need to catch. What do you think?

@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Dec 5, 2025
@gagantrivedi gagantrivedi force-pushed the feat/experimental-flag-update-endpoints branch from 610dba4 to 2b78c5e Compare December 5, 2025 06:00
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Dec 5, 2025
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Dec 5, 2025
@gagantrivedi gagantrivedi requested a review from emyller December 5, 2025 07:24
@khvn26 khvn26 self-assigned this Dec 8, 2025
@khvn26 khvn26 self-requested a review December 8, 2025 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create new experimental endpoints to update a given feature in an environment

5 participants