feat(router): regex selectors for subgraph header rules (subgraph_patterns)#2868
feat(router): regex selectors for subgraph header rules (subgraph_patterns)#2868mwisner wants to merge 1 commit into
Conversation
Adds an ordered `subgraph_patterns` list under `headers` whose `matching` field is a Go regex applied to the subgraph name. Patterns are evaluated after `headers.all` and before exact `headers.subgraphs.<name>` rules, letting a single rule cover a base subgraph and its feature subgraphs without duplicating per-subgraph blocks for every preview deployment. Pattern regexes are compiled once at startup; invalid regexes fail `NewHeaderPropagation`. Existing configs without `subgraph_patterns` hit a fast-path and pay no additional cost.
WalkthroughThis PR extends the router's header propagation engine to support pattern-based rule matching on subgraph names via Go regexes. Rules are evaluated in order: global rules, then matching pattern rules (with optional negation), then exact per-subgraph rules. Both request and response header paths are updated. ChangesSubgraph Pattern Header Rules
🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
docs-website/router/proxy-capabilities/subgraph-request-header-operations.mdx (1)
70-70: ⚡ Quick winSplit this into two short reference sentences.
Line 70 is dense for reference-style docs. Split the example rationale into two short statements.
As per coding guidelines, "Prefer short, declarative sentences. If a sentence has more than one comma-separated clause, consider splitting it."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs-website/router/proxy-capabilities/subgraph-request-header-operations.mdx` at line 70, The sentence explaining subgraph_patterns and matching is too dense; split it into two short declarative sentences: first state that the subgraph_patterns section applies rules to every subgraph whose name matches the regular expression in matching, and then add a second sentence giving the example rationale (e.g., this is useful for targeting a base subgraph and its feature subgraphs such as PR-preview deployments named products-feature-pr-123) so the explanation is clear and concise while keeping the reference focused on subgraph_patterns and matching.docs-website/router/proxy-capabilities/subgraph-response-header-operations.mdx (1)
82-82: ⚡ Quick winBreak precedence details into a short list.
This line packs multiple distinct facts into one sentence. In reference docs, a short sentence plus a 3-item order list is easier to scan.
As per coding guidelines, "Use structured lists when presenting multiple distinct items. Do not pack them into a single paragraph."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs-website/router/proxy-capabilities/subgraph-response-header-operations.mdx` at line 82, Replace the dense sentence describing precedence in the subgraph_patterns paragraph with a short leading sentence and a three-item ordered list; explicitly state that patterns are evaluated: 1) after the all rules, 2) before exact subgraphs rules, and 3) that exact subgraphs can still override a matching pattern (referencing the terms subgraph_patterns, matching, all, and subgraphs to locate the text).router/core/header_rule_engine.go (1)
996-1000: ⚖️ Poor tradeoffConsider recompiling regexes on the request path.
SubgraphRulesrecompiles pattern regexes on every call (lines 996-1000), while the main engine pre-compiles them once at startup inNewHeaderPropagation(lines 190-210). IfFetchURLRules(which calls this function) is invoked frequently during request processing, repeated regex compilation could add latency proportional to the number of patterns.The PR objectives note this as an open question: "sharing compiled regexes between helpers." Since
SubgraphRulesis a package-level function, it cannot access the pre-compiledHeaderPropagation.subgraphPatternRegexslice. Alternatives include making it a method, passing regexes as parameters, or introducing a package-level cache.However, if measurements confirm the current approach adds negligible latency (as the PR objectives suggest: "<10 µs in examples"), this tradeoff may be acceptable for API simplicity.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@router/core/header_rule_engine.go` around lines 996 - 1000, SubgraphRules currently recompiles patterns on each call; change it to accept and use precompiled regexes instead (e.g., pass a []*regexp.Regexp or a map of pattern->*regexp.Regexp) so callers like FetchURLRules can forward HeaderPropagation.subgraphPatternRegex produced in NewHeaderPropagation; alternatively make SubgraphRules a method on HeaderPropagation that uses the existing subgraphPatternRegex field; update all call sites to supply the precompiled slice and remove the regexp.Compile(...) logic and associated continue branch inside SubgraphRules.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@docs-website/router/proxy-capabilities/subgraph-request-header-operations.mdx`:
- Around line 86-89: The list items for the selectors (`matching`,
`negate_match`, `request`, `response`) use em dashes; update each bullet in
subgraph-request-header-operations.mdx to remove the em dash and follow the MDX
docs style (replace the em dash with a period or rephrase into a short
sentence), e.g. "`matching` — A Go regular expression..." → "`matching`. A Go
regular expression..." ensuring punctuation and capitalization remain consistent
across all four entries.
---
Nitpick comments:
In
`@docs-website/router/proxy-capabilities/subgraph-request-header-operations.mdx`:
- Line 70: The sentence explaining subgraph_patterns and matching is too dense;
split it into two short declarative sentences: first state that the
subgraph_patterns section applies rules to every subgraph whose name matches the
regular expression in matching, and then add a second sentence giving the
example rationale (e.g., this is useful for targeting a base subgraph and its
feature subgraphs such as PR-preview deployments named products-feature-pr-123)
so the explanation is clear and concise while keeping the reference focused on
subgraph_patterns and matching.
In
`@docs-website/router/proxy-capabilities/subgraph-response-header-operations.mdx`:
- Line 82: Replace the dense sentence describing precedence in the
subgraph_patterns paragraph with a short leading sentence and a three-item
ordered list; explicitly state that patterns are evaluated: 1) after the all
rules, 2) before exact subgraphs rules, and 3) that exact subgraphs can still
override a matching pattern (referencing the terms subgraph_patterns, matching,
all, and subgraphs to locate the text).
In `@router/core/header_rule_engine.go`:
- Around line 996-1000: SubgraphRules currently recompiles patterns on each
call; change it to accept and use precompiled regexes instead (e.g., pass a
[]*regexp.Regexp or a map of pattern->*regexp.Regexp) so callers like
FetchURLRules can forward HeaderPropagation.subgraphPatternRegex produced in
NewHeaderPropagation; alternatively make SubgraphRules a method on
HeaderPropagation that uses the existing subgraphPatternRegex field; update all
call sites to supply the precompiled slice and remove the regexp.Compile(...)
logic and associated continue branch inside SubgraphRules.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0536864b-3573-4100-bad3-413e19a623c4
📒 Files selected for processing (9)
docs-website/router/proxy-capabilities/subgraph-request-header-operations.mdxdocs-website/router/proxy-capabilities/subgraph-response-header-operations.mdxrouter/core/header_rule_engine.gorouter/core/header_rule_engine_buildheader_test.gorouter/core/header_rule_engine_test.gorouter/pkg/config/config.gorouter/pkg/config/config.schema.jsonrouter/pkg/config/testdata/config_defaults.jsonrouter/pkg/config/testdata/config_full.json
| * `matching` — A Go regular expression evaluated against the subgraph name. Required. | ||
| * `negate_match` — If `true`, the regex result is inverted. Useful for "all subgraphs except X" rules. | ||
| * `request` — Request rules to apply when the pattern matches. | ||
| * `response` — Response rules to apply when the pattern matches. |
There was a problem hiding this comment.
Replace em dashes in selector bullets.
The bullets use em dashes, which conflicts with the docs style rule for MDX files.
Suggested edit
-* `matching` — A Go regular expression evaluated against the subgraph name. Required.
-* `negate_match` — If `true`, the regex result is inverted. Useful for "all subgraphs except X" rules.
-* `request` — Request rules to apply when the pattern matches.
-* `response` — Response rules to apply when the pattern matches.
+* `matching`: A Go regular expression evaluated against the subgraph name. Required.
+* `negate_match`: If `true`, the regex result is inverted. Useful for "all subgraphs except X" rules.
+* `request`: Request rules to apply when the pattern matches.
+* `response`: Response rules to apply when the pattern matches.As per coding guidelines, "Avoid em dashes. Use periods or restructure the sentence instead."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| * `matching` — A Go regular expression evaluated against the subgraph name. Required. | |
| * `negate_match` — If `true`, the regex result is inverted. Useful for "all subgraphs except X" rules. | |
| * `request` — Request rules to apply when the pattern matches. | |
| * `response` — Response rules to apply when the pattern matches. | |
| * `matching`: A Go regular expression evaluated against the subgraph name. Required. | |
| * `negate_match`: If `true`, the regex result is inverted. Useful for "all subgraphs except X" rules. | |
| * `request`: Request rules to apply when the pattern matches. | |
| * `response`: Response rules to apply when the pattern matches. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@docs-website/router/proxy-capabilities/subgraph-request-header-operations.mdx`
around lines 86 - 89, The list items for the selectors (`matching`,
`negate_match`, `request`, `response`) use em dashes; update each bullet in
subgraph-request-header-operations.mdx to remove the em dash and follow the MDX
docs style (replace the em dash with a period or rephrase into a short
sentence), e.g. "`matching` — A Go regular expression..." → "`matching`. A Go
regular expression..." ensuring punctuation and capitalization remain consistent
across all four entries.
Why
Today, subgraph-specific header rules in the router are matched by exact subgraph name. Feature subgraphs are composed under their own name (e.g.
products-feature-v2) rather than the base subgraph's name (products), so per-subgraph rules defined for the base subgraph do not apply to its feature variants. Onlyheaders.allrules carry over automatically.There are two existing options for handling header propagation to feature subgraphs:
Use
headers.all. This applies the rule to every subgraph regardless of name, so feature subgraphs are covered. The trade-off is that the rule is also applied to every other subgraph in the graph — including subgraphs that have no need for the header. For users who treat subgraph header lists as an explicit allow-list (to avoid leaking headers to subgraphs that shouldn't see them, or to keep request-deduplication keys tight), this is broader than they want.Add a separate
headers.subgraphs.<feature-name>block for each feature subgraph. This works and is precise, but the rule has to be authored statically against each feature subgraph name. For workflows where feature subgraphs are short-lived or numerous (for example, per-branch or per-PR feature subgraphs), this means router config edits and a router redeploy each time a feature subgraph is created or renamed. Without hot reload, that affects all GraphQL traffic for what should be a localized change.This PR adds an opt-in third option: regex selectors that target a group of subgraphs by name. A single rule can cover a base subgraph and its feature variants without listing each one.
What
A new ordered list
headers.subgraph_patternswhosematchingfield is a Go regex evaluated against the subgraph name.Schema example
Before — a rule under
subgraphs.productsonly matches the literal nameproducts:After — a single pattern entry covers the base subgraph and every feature variant:
negate_match: trueis also supported, mirroring how it already works on header-name regexes:Rule evaluation order
For each subgraph the router builds a header set in this order:
headers.allrulesheaders.subgraph_patternsentries whose regex matches the subgraph name (in config order)headers.subgraphs.<name>rules for the exact subgraph nameExact-name rules apply last so they can still override a broader pattern rule (e.g. via
op: set). This matches how the existing two layers compose today.Backward compatibility
No breaking changes.
subgraph_patternsis a new optional field. Configs without it behave identically to before.headers.subgraphs.<name>continues to match by exact name with no semantic change.subgraph_patternsis empty (hasAnyPatternRequestRules == false), so existing users see zero added work per request.Performance
The hot path is
BuildRequestHeaderForSubgraph, called per data source in the execution plan viaSubgraphHeadersBuilder.subgraph_patternshasAnyPatternRequestRulesshort-circuitnpatterns configured, plan touchesksubgraphsk × nregex.MatchStringcalls per built header setConcrete properties:
NewHeaderPropagation, stored insubgraphPatternRegex []*regexp.Regexp. Invalid regexes fail router init rather than at request time.regexpuses RE2, which is linear-time and rejects backtracking constructs.n ≤ 5,k ≤ 20, names ~30 chars) this adds <10 µs per request, well below surrounding planning cost.SubgraphRuleshelper (called during engine factory init, not on the request path) re-compiles pattern regexes per call. Easy to share the pre-compiled regexes if reviewers prefer; left as-is to keep the diff focused.Implementation summary
router/pkg/config/config.goSubgraphPatternHeaderRuletype andHeaderRules.SubgraphPatternsfieldrouter/core/header_rule_engine.gohasRequestRulesForSubgraphandSubgraphRulesrouter/pkg/config/config.schema.jsonheaders.subgraph_patternsrouter/pkg/config/testdata/*.jsonrouter/core/header_rule_engine_test.gorouter/core/header_rule_engine_buildheader_test.gonegate_match, invalid regex, missingmatching, all → patterns → exact ordering, pattern-only fast-path,SubgraphRuleshelper coveragedocs-website/router/proxy-capabilities/subgraph-request-header-operations.mdxdocs-website/router/proxy-capabilities/subgraph-response-header-operations.mdxValidation
Locally on darwin/arm64 with Go 1.26.3:
Notes for reviewers
subgraphs:with a sigil instead of a separate top-level list). Wanted to keep it explicit and additive to avoid colliding with existing exact-name rules.SubgraphRulesshare the pre-compiled regex slice withHeaderPropagationinstead of recompiling? Easy follow-up; called out above.proto/wg/cosmo/node/v1/node.protoonly carriesSubgraph{id, name, routing_url}, so feature-subgraph → base-subgraph linkage would need execution-config changes and a clearer compatibility story. Regex selectors are router-local and additive.