Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 23, 2025

Problem

Currently, flagd services have inconsistent handling of selectors:

  • Sync Service: Uses selector field from the request body
  • Evaluation Service (v1 & v2): Uses Flagd-Selector header
  • OFREP Service: Uses Flagd-Selector header

This inconsistency makes the API surface less predictable and can lead to confusion for users.

Solution

This PR normalizes selector handling by updating the sync service to accept the Flagd-Selector header as the primary method, aligning it with the evaluation and OFREP services. The implementation maintains full backward compatibility by falling back to the request body selector when the header is not present.

Changes

Core Implementation

Modified flagd/pkg/service/flag-sync/handler.go:

  • Added getSelectorExpression() helper method that checks for Flagd-Selector header (via gRPC metadata) first
  • Falls back to request body selector field if header is not present
  • Logs a deprecation warning when the request body selector is used
  • Applied the new logic to both SyncFlags() and FetchAllFlags() methods

Test Coverage

Added 5 comprehensive test cases in handler_test.go:

  • Header-based selector (verifies no deprecation warning)
  • Request body selector (verifies backward compatibility and deprecation warning)
  • Header precedence (verifies header takes priority when both are provided)
  • FetchAllFlags with header selector
  • FetchAllFlags with request body selector

All existing tests continue to pass.

Migration Path

The change is fully backward compatible. Users can migrate at their convenience:

Current (deprecated):

req := &syncv1.FetchAllFlagsRequest{
    Selector: "source:my-source",
}
resp, err := client.FetchAllFlags(ctx, req)

Recommended:

md := metadata.New(map[string]string{
    "Flagd-Selector": "source:my-source",
})
ctx := metadata.NewOutgoingContext(context.Background(), md)
req := &syncv1.FetchAllFlagsRequest{}
resp, err := client.FetchAllFlags(ctx, req)

Benefits

  • Consistency: All flagd services now use the same Flagd-Selector header pattern
  • Backward Compatibility: Existing clients continue to work without modification
  • Clear Migration Path: Deprecation warnings guide users to adopt the new approach
  • Aligns with Standards: Using headers/metadata for query/filter parameters is a common gRPC pattern

Breaking Changes

None. The request body selector will be removed in a future major version (e.g., v2.0.0).

Related

Addresses #[issue_number]

Original prompt

This section details on the original issue you should resolve

<issue_title>[FEATURE] Normalize selector handling across sync, evaluation, and OFREP services</issue_title>
<issue_description>### Requirements

Problem

Currently, we have inconsistent handling of selectors across different flagd services:

  • Sync Service (flagd/pkg/service/flag-sync/handler.go:34): Uses req.GetSelector() from the request body
  • Evaluation Service: Uses flagd-selector header
  • OFREP Service: Uses flagd-selector header

This inconsistency can lead to confusion for users and makes the API surface less predictable.

Proposal

Normalize selector handling across all services by:

  1. Preferred approach: Use the flagd-selector header as the primary method for all services
  2. Backward compatibility: For the sync service, continue to accept selector in the request body as a fallback for a deprecation period

Implementation Strategy

  1. Update sync service to check for flagd-selector header first
  2. Fall back to request body selector field if header is not present
  3. Log deprecation warning when using request body selector
  4. Document the change and migration path
  5. Remove request body selector support in a future major version (e.g., v2.0.0)

Benefits

  • Consistent API across all flagd services
  • Easier to understand and use for developers
  • Aligns with common patterns for query/filter parameters in gRPC metadata

Breaking Changes

None initially (backward compatible), but request body selector would be removed in a future major release.

Additional Context

The sync service currently processes the selector at:

selectorExpression := req.GetSelector()
selector := store.NewSelector(selectorExpression)

This should be updated to prioritize metadata/header values while maintaining backward compatibility.</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #1814


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Relates to: open-feature/flagd-schemas#199

@netlify
Copy link

netlify bot commented Oct 23, 2025

Deploy Preview for polite-licorice-3db33c ready!

Name Link
🔨 Latest commit a968b90
🔍 Latest deploy log https://app.netlify.com/projects/polite-licorice-3db33c/deploys/690b7fe16edc770008e10325
😎 Deploy Preview https://deploy-preview-1815--polite-licorice-3db33c.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@aepfli
Copy link
Member

aepfli commented Oct 23, 2025

/Gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request normalizes selector handling in the sync service to align with other services, prioritizing the Flagd-Selector header while maintaining backward compatibility with the request body selector. The changes are well-implemented and include comprehensive tests for all scenarios. My review includes a few suggestions to refactor the new logic and test code for improved maintainability and to reduce duplication.

Copilot AI changed the title [WIP] Normalize selector handling across services Normalize selector handling across sync, evaluation, and OFREP services Oct 23, 2025
Copilot AI requested a review from aepfli October 23, 2025 20:07
Copilot finished work on behalf of aepfli October 23, 2025 20:07
@aepfli aepfli changed the title Normalize selector handling across sync, evaluation, and OFREP services feat: Normalize selector handling across sync, evaluation, and OFREP services Oct 24, 2025
@toddbaert toddbaert changed the title feat: Normalize selector handling across sync, evaluation, and OFREP services feat: normalize selector in sync (use header as in OFREP and RPC) Oct 29, 2025
@toddbaert toddbaert force-pushed the copilot/normalize-selector-handling branch from 89372a9 to 65f9b6a Compare October 29, 2025 20:22
@toddbaert
Copy link
Member

/gemini review

@toddbaert toddbaert marked this pull request as ready for review October 29, 2025 20:22
@toddbaert toddbaert requested review from a team as code owners October 29, 2025 20:22
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Oct 29, 2025
@toddbaert
Copy link
Member

toddbaert commented Oct 29, 2025

I pushed some changes in tests and reverted the go.mod/sum files.

I manually tested this and it works as expected.

@toddbaert toddbaert self-requested a review October 29, 2025 20:23
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully normalizes selector handling in the sync service by prioritizing the Flagd-Selector header over the request body, which aligns it with other services. The implementation is backward compatible and includes new tests. My review focuses on two main points: ensuring the deprecation warning for the body selector is logged at an appropriate level (Warn instead of Debug) and enhancing the tests to verify that this warning is correctly emitted. These changes will improve user guidance and test coverage.

Copilot AI and others added 7 commits November 5, 2025 11:48
Co-authored-by: aepfli <9987394+aepfli@users.noreply.github.com>
Co-authored-by: aepfli <9987394+aepfli@users.noreply.github.com>
Co-authored-by: aepfli <9987394+aepfli@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@toddbaert toddbaert force-pushed the copilot/normalize-selector-handling branch from b597dae to a968b90 Compare November 5, 2025 16:48
@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 5, 2025

@toddbaert toddbaert merged commit c1f06cb into main Nov 5, 2025
18 checks passed
@github-actions github-actions bot mentioned this pull request Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Normalize selector handling across sync, evaluation, and OFREP services

4 participants