Skip to content

Conversation

kamilkisiela
Copy link
Contributor

@kamilkisiela kamilkisiela commented Sep 19, 2025

Implements #318

This is the flow the PR introduces:

Config -> Compile -> Plan -> Apply

Config gets Compiled into a Plan that is Applied when needed (when request occurs).

In the compilation step, we validate the config and produce an immutable plan.
Regexes are combined and compiled to have the matching more efficient.
In this step, we also produce a list of header manipulation operations, in order of their definition in the config.

The response headers are collected after every subgraph response. We don't hold them forever, we only keep the relevant ones, by aggregating them response by response.


Release note

Advanced Header Management: You can now declaratively control HTTP headers for both subgraph requests and client responses. The new headers configuration allows for fine-grained manipulation, including:

  • Global and Per-Subgraph Rules: Define rules that apply to all subgraphs or specify overrides for individual ones.
  • Propagation Control: Forward headers with the ability to rename them or provide default values if they are not present.
  • Header Insertion with Expressions: Insert or overwrite headers with static values or dynamic values generated using VRL expressions.
  • Response Header Aggregation: Control how response headers from multiple subgraphs are merged using first, last, or append strategies.
  • Flexible Matching: Apply rules to headers based on exact names, regular expressions, and exclusion patterns.
    headers:
      all:
        request:
          - propagate:
              named: Authorization
      subgraphs:
        accounts:
          request:
            - propagate:
                named: x-tenant-id
                rename: x-acct-tenant
                default: "default-tenant"
        users:
          request:
            - insert:
                name: x-user-id
                expression: .request.headers."x-user-id" || "anonymous"
    

Copy link

github-actions bot commented Sep 19, 2025

k6-benchmark results

     ✓ response code was 200
     ✓ no graphql errors
     ✓ valid response structure

     █ setup

     checks.........................: 100.00% ✓ 254568      ✗ 0    
     data_received..................: 7.4 GB  248 MB/s
     data_sent......................: 100 MB  3.3 MB/s
     http_req_blocked...............: avg=2.74µs   min=699ns   med=1.7µs   max=4.01ms   p(90)=2.42µs  p(95)=2.73µs  
     http_req_connecting............: avg=257ns    min=0s      med=0s      max=1.4ms    p(90)=0s      p(95)=0s      
     http_req_duration..............: avg=17.3ms   min=1.56ms  med=16.37ms max=214.12ms p(90)=24ms    p(95)=26.77ms 
       { expected_response:true }...: avg=17.3ms   min=1.56ms  med=16.37ms max=214.12ms p(90)=24ms    p(95)=26.77ms 
     http_req_failed................: 0.00%   ✓ 0           ✗ 84876
     http_req_receiving.............: avg=185.95µs min=25.09µs med=41.61µs max=189.22ms p(90)=79.27µs p(95)=361.63µs
     http_req_sending...............: avg=22.38µs  min=4.43µs  med=9.74µs  max=21.86ms  p(90)=14.55µs p(95)=22.25µs 
     http_req_tls_handshaking.......: avg=0s       min=0s      med=0s      max=0s       p(90)=0s      p(95)=0s      
     http_req_waiting...............: avg=17.09ms  min=1.5ms   med=16.25ms max=52.26ms  p(90)=23.74ms p(95)=26.45ms 
     http_reqs......................: 84876   2824.595375/s
     iteration_duration.............: avg=17.66ms  min=3.56ms  med=16.68ms max=242.47ms p(90)=24.4ms  p(95)=27.21ms 
     iterations.....................: 84856   2823.929793/s
     vus............................: 50      min=50        max=50 
     vus_max........................: 50      min=50        max=50 

Copy link

github-actions bot commented Sep 19, 2025

🐋 This PR was built and pushed to the following Docker images:

Image Names: ghcr.io/graphql-hive/router

Platforms: linux/amd64,linux/arm64

Image Tags: ghcr.io/graphql-hive/router:pr-438 ghcr.io/graphql-hive/router:sha-7ee8e9e

Docker metadata
{
"buildx.build.ref": "builder-53ce41be-6822-4e03-8c43-65599699abb8/builder-53ce41be-6822-4e03-8c43-65599699abb80/6hk9b34z85nlbv4n29whl75kn",
"containerimage.descriptor": {
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "digest": "sha256:c938e3950c0308d4f67ccf34ef62bf6f06f633ce964d6f9e84839c458123b608",
  "size": 1609
},
"containerimage.digest": "sha256:c938e3950c0308d4f67ccf34ef62bf6f06f633ce964d6f9e84839c458123b608",
"image.name": "ghcr.io/graphql-hive/router:pr-438,ghcr.io/graphql-hive/router:sha-7ee8e9e"
}

@kamilkisiela kamilkisiela changed the title Add header configuration to the router config Add request and response headers manipulation Sep 23, 2025
@kamilkisiela

This comment was marked as outdated.

gemini-code-assist[bot]

This comment was marked as outdated.

@kamilkisiela

This comment was marked as outdated.

gemini-code-assist[bot]

This comment was marked as outdated.

@kamilkisiela kamilkisiela marked this pull request as ready for review September 24, 2025 13:50
@kamilkisiela kamilkisiela changed the title Add request and response headers manipulation feat(router): Advanced Header Management Sep 26, 2025
@kamilkisiela
Copy link
Contributor Author

/gemini review
/gemini summary

Copy link
Contributor

Hello @kamilkisiela, I received your commands /gemini review and /gemini summary. While I don't execute commands in that specific format, I understand you're looking for a review and a summary of this pull request. I've analyzed the changes and here's my feedback:

Overall Impression

This pull request introduces a significant and well-designed feature for advanced header management within the router. The approach of compiling header rules into an immutable plan and then applying them at runtime is robust and efficient. The use of VRL expressions for dynamic header values adds a powerful layer of flexibility, and the clear separation of concerns into dedicated modules for compilation, planning, and application is excellent for maintainability. The comprehensive documentation for the new configuration is also a major plus.

Review based on criteria:

Correctness

  • Header Management Flow: The PR correctly implements the "Config -> Compile -> Plan -> Apply" flow. Configuration is compiled into a HeaderRulesPlan during RouterSharedState initialization, and this plan is then used to modify headers for both outgoing subgraph requests and incoming client responses.
  • Error Handling: The RouterSharedState::new now returns a Result, allowing for proper error propagation if header rule compilation fails. New error types (HeaderRuleCompileError, HeaderRuleRuntimeError) are introduced, which is good practice.
  • Response Handling: The execute_plan function now returns PlanExecutionOutput which correctly encapsulates both the response body and headers, ensuring that header manipulation is integrated into the execution pipeline.
  • Deduplication Logic: The request_fingerprint function in dedupe.rs has been updated to consider all request headers (using BTreeMap for consistent hashing), which improves the correctness of request deduplication.

Efficiency

  • Pre-compilation: Header rules, including regexes and VRL expressions, are compiled once when the router state is initialized. This minimizes runtime overhead, as the compiled plan can be efficiently applied to each request/response.
  • Optimized Header Joining: The join_with_comma function in response.rs includes a capacity calculation for the Vec<u8>, which is a small but effective optimization for concatenating header values.
  • Targeted Application: Header rules are applied in a targeted manner (global then subgraph-specific), ensuring that only relevant rules are processed.

Maintainability

  • Modular Design: The new headers module is well-structured with submodules for compile, errors, expression, plan, request, response, and sanitizer. This promotes code organization and makes the feature easier to understand and extend.
  • Declarative Configuration: The YAML-based header configuration is declarative and intuitive, allowing users to define complex header manipulation rules without modifying router code.
  • VRL Expressions: The integration of VRL expressions provides a powerful and flexible mechanism for dynamic header values, reducing the need for custom code changes for common use cases.
  • Comprehensive Documentation: The docs/README.md file has been extensively updated with detailed explanations and examples of the new header configuration, which is crucial for user adoption and understanding.

Security

  • Header Sanitization: The sanitizer.rs module explicitly defines and enforces rules for HOP_BY_HOP_HEADERS (which are always stripped) and NEVER_JOIN_HEADERS (which are never comma-joined). This is a critical security measure to prevent header-related vulnerabilities and ensure correct HTTP behavior.

Summary

This pull request delivers a robust and highly configurable header management system. By introducing a clear

Initial code for response headers

Add subgraph header middleware

Refactor response header handling

Fix header error messages and improve clarity

descriptions

no default algo

Adds expressions to headers propagation (#453)

tests

snaps

slight adjustments to config to make it simpler
@dotansimha dotansimha merged commit a40dfcf into main Oct 6, 2025
18 checks passed
@dotansimha dotansimha deleted the kamil-header-prop branch October 6, 2025 07:58
This was referenced Oct 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants