Skip to content

Conversation

@matthewelwell
Copy link
Contributor

@matthewelwell matthewelwell commented Oct 29, 2025

Changes

Contributes to #6029

Adds a new endpoint to update a flag in a given environment, regardless of whether versioning is used or not.

The reasoning behind creating a new endpoint is:

  1. The API interactions to update a flag in a versioned environment are very convoluted
  2. The current API for updating a flag in a non-versioned environment relies on crud interactions from the django box of tricks

The new endpoint will look something like this:

POST /environments/:id/features/:feature_name/update-flag

{
  "enabled": bool,
  "value": string,
  "type": OneOf["string" | "integer" | ...],
  "segment_id": number | null,
  "multivariate": TODO
}

Other thoughts / outstanding questions:

  1. Should the URL use the environment key, or the environment ID? (realistically, it would be fairly easy to do both here by creating 2 endpoints that route to the same logic under the hood, only the environment retrieval changes)
  2. Do we want to add a separate bulk update endpoint here, or perhaps make this endpoint support bulk operations?
  3. We still need to implement this functionality for multivariate values, but I don't think that will be too difficult.
  4. Should this create the flag if it doesn't already exist (in the case of a segment override)
    a. How does the current create-segment-override endpoint currently behave in a versioned environment?
  5. Error handling?
    a. We need to consider the following scenarios here:
    i. Flag is in a release pipeline - this should definitely error
    ii. Flag has a scheduled change - should this error?
    iii. Change requests are enabled for the environment.

Based on question (2), we could instead have the endpoint look something like:

POST /environments/:id/update-flags/

{
  "data": [
    {
      "feature_name": string,
      "enabled": bool,
      "value": string,
      "type": OneOf["string" | "integer" | ...],
      "segment_id": number | null,
      "multivariate": TODO
    },
    ...
  ]
}

Or even, taking (2) into account:

POST /bulk-update-flags/

{
  "data": {
    "environment_id": number,
    "environment_key": string,
    "flag_updates": [
      {
        "feature_name": string,
        "enabled": bool,
        "value": string,
        "type": OneOf["string" | "integer" | ...],
        "segment_id": number | null,
        "multivariate": TODO
      },
      ...
    ]
  }
}

Note: exactly one of environment_id, or environment_key is required.

Answered questions

  1. Can we just reimplement the current endpoint to update a feature state in v1? Although we're using Django's crud functionality, we could theoretically pull that method out of the ViewSet, and reimplement ourselves. This would probably be an AND, rather than an instead though as I think adding this generic endpoint still gives us more flexibility.

Looking into this, the existing endpoint relies on sending a PUT to the endpoint /environments/:key/featurestates/:id which relies on the ID of the feature state itself. Since we'd be creating a new feature state as part of the logic for a v2 versioned environment (and hence changing the ID), this would either be really bad UX, or just wouldn't work.

  1. Should the URL use the feature name, or the ID?

We agreed the URL shouldn't include the feature at all, and the name should be included in the payload. The URL will just be /environments/:key|id/update-flag

How did you test this code?

Added a basic unit test, but more tests will need to be added when this becomes a real change that we want to make.

@vercel
Copy link

vercel bot commented Oct 29, 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 Oct 29, 2025 10:48am
flagsmith-frontend-preview Ignored Ignored Oct 29, 2025 10:48am
flagsmith-frontend-staging Ignored Ignored Oct 29, 2025 10:48am

@github-actions github-actions bot added api Issue related to the REST API feature New feature or request labels Oct 29, 2025
@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

❌ Patch coverage is 92.66055% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.99%. Comparing base (71bf912) to head (4ea79aa).
⚠️ Report is 21 commits behind head on main.

Files with missing lines Patch % Lines
api/features/versioning/versioning_service.py 78.94% 8 Missing ⚠️

❌ Your patch status has failed because the patch coverage (92.66%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6221      +/-   ##
==========================================
- Coverage   98.01%   97.99%   -0.02%     
==========================================
  Files        1278     1280       +2     
  Lines       45138    45285     +147     
==========================================
+ Hits        44240    44378     +138     
- Misses        898      907       +9     

☔ 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.

default="string",
)

segment_id = serializers.IntegerField(required=False)
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to provide priority here as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed we @gagantrivedi, we plan to focus on the environment default case for now, and ignore for segments for now. The logic behind this is it creates a much more streamlined endpoint here for users that don't care about segments.

We could then either:

  1. Update this endpoint to include segment information if we get feedback that it should
  2. Create another similar endpoint which handles this for a specific segment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On further discussions, we have gone back to accommodating segment overrides in this endpoint.

We should make priority optional (if the priority is missing, it just gets added to the end of the list). We see that there are 2 main use cases here:

  1. Send "priority": 1 to add it to the top of the list
  2. Send "priority": null (or don't send) and the segment is added to the end of the list.

The endpoint should handle creating or updating a segment override, and should return in the response payload whether the change was an update or not (the status code should still be 200).

name="edge-identity-overrides",
),
path(
"<int:environment_id>/features/<str:feature_name>/update-flag/",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again, as discussed with @gagantrivedi, let's remove the feature name from the URL since there is nothing stopping it containing HTTP reserved characters. The endpoint should therefore be:

POST /environments/:key/update-flag

{
  "feature_name": "foo",
  ...
}

@matthewelwell
Copy link
Contributor Author

Closing this PR in favour of creating a more complete version as part of #6233

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.

3 participants