版本发布 8
## Fixes ### Fix: Traverse fragments linearly during cycle validation and inlining GraphQL fragments can spread other fragments, e.g. `fragment A on T { ...B }`. When fragments form a long acyclic chain (A spreads B, B spreads C, and so on for thousands of links), we walked that chain with plain recursion. This change prevents the stack from being filled in such cases.
## Fixes ### Implement Circuit Breaker for Subgraph Requests This change introduces a circuit breaker mechanism for subgraph requests in the Hive Router. The circuit breaker will monitor the success and failure rates of requests to each subgraph and will prevent future requests if the failure rate exceeds a certain threshold. When the circuit breaker is opened, subsequent requests to that subgraph will fail immediately without attempting to send the request. This implementation helps improve the resilience and stability of the Hive Router when dealing with unreliable subgraphs. ### Record subgraph execution errors on the `graphql.subgraph.operation` span Errors raised while preparing or executing a subgraph fetch (`PlanExecutionError`) are now attached to the corresponding `graphql.subgraph.operation` span instead of only surfacing on the top-level `graphql.operation` span via the response-error pipeline. For each failing fetch the span now carries: - `hive.graphql.error.count = 1`, - `hive.graphql.error.codes` set to the error code (e.g. `SUBGRAPH_REQUEST_TIMEOUT`, `HEADER_PROPAGATION_FAILURE`, `SUBGRAPH_CIRCUIT_BREAKER_REJECTED`, …), and - a `graphql.error` event with `error.type`, `error.message`, and `hive.error.subgraph_name`. Previously these subgraph-level spans looked "ok" even when the fetch never produced a response, which was misleading in tracing UIs that highlight failing spans. The error is now visible at the subgraph hop where it actually originated.
## Fixes ### Preserve custom scalars as raw JSON Custom scalar fields marked by the query planner are now preserved as raw JSON instead of being parsed and rebuilt as structured response values. This improves correctness for JSON passthrough custom scalars while avoiding performance regressions for normal response handling.
## Fixes - Adjustments in operation's kind being Enum and not &'static str ### Added missing `isRepeatable` on `type __Directive` The router's introspection schema was resolving `isRepeatable`, but it did not appear in the public (consumer) schema, leading to validation errors when introspection schema was executed through Laboratory. This change adds the missing `isRepeatable: Boolean!` to `type __Directive`, according to the [GraphQL introspection spec](https://github.com/graphql/graphql-spec/blob/main/spec/Section%204%20--%20Introspection.md). ### Avoid propagating `@include`/`@skip` conditions to unconditional fetches Fixed query planner condition propagation logic to avoid wrapping unconditional fetches in conditional blocks when merging steps. This ensures that fields without directives are not incorrectly gated by conditions from other steps, allowing for correct execution of queries with mixed conditional and unconditional selections. ### Fix fragments being dropped when multiple inline fragments target the same concrete type within an abstract type fragment. Previously, when a query contained two or more inline fragments on the same concrete type nested inside an interface or union fragment, only the first fragment's fields were included in the query plan — all subsequent ones were silently dropped. **Example query that previously returned only `title`:** ```graphql query { films { ... on Node { ... on Film { title } ... on Film { director } } } } ``` Both fields are now correctly returned. ### Fix fragment handling Fix fragment handling for some queries that use reusable fragments with conditional directives
## Features ### Improve HTTP server request OTel tracing with client and peer network attributes. The `http.server` span now includes: - `client.address` and `client.port` from a configurable request header - `network.peer.address` and `network.peer.port` from the address of the incoming connection ```yaml telemetry: client_identification: # Default - use socket peer only ip_header: null # Header name - use the left-most valid IP from the header ip_header: x-forwarded-for # Trusted proxies - only trust the header when the socket peer is trusted ip_header: name: x-forwarded-for trusted_proxies: - 10.0.0.0/8 - 192.168.0.0/16 ``` In trusted proxies scenario, the Router scans the configured header from right to left, skips trusted proxy IP ranges, and records the first non-trusted IP as `client.address`. If no valid client IP can be resolved, the Router falls back to the socket peer address. ### Coprocessors Introduces Coprocessors as language agnostic way to extend Hive Router. **Supports coprocessor stages:** - `router.request` - `router.response` - `graphql.request` - `graphql.analysis` - `graphql.response` **Stage capabilities:** - include selected request/response fields in stage payloads (headers, body, context, and optional SDL depending on stage config) - mutate request body/headers/context for downstream pipeline execution - short-circuit and return an immediate HTTP response from a stage **Transport and endpoint support:** - `http://` and `unix://` (unix socket domain) endpoints - http/1, http/2 and h2c protocols **Error handling:** - coprocessor failures map to server-side failures (500) - client-facing GraphQL errors are masked as Internal server error - structured error codes are preserved in GraphQL extensions.code - detailed coprocessor failure reasons remain in server logs/telemetry only **Adds coprocessor metrics:** - hive.router.coprocessor.requests_total - hive.router.coprocessor.duration - hive.router.coprocessor.errors_total ## Fixes - Adjustments in operation's kind being Enum and not &'static str ### Dynamic Exclusions ## Dynamic Exclusions in Hive Router Hive Router now supports dynamic exclusions, allowing you to exclude specific requests from usage reporting based on custom logic. This feature is useful for scenarios where you want to skip telemetry for certain requests, such as health checks or specific endpoints. The previous operation-name list format is still supported for backward compatibility. ### Usage ```diff - exclude: ['ExcludedOp'] + exclude: + expression: '.request.operation.name == "ExcludedOp"' ``` Both of the following are valid and supported: ```yaml # legacy format exclude: - ExcludedOp # dynamic expression format exclude: expression: '.request.operation.name == "ExcludedOp"' ``` The details about expression context is documented in the [Hive Router documentation](https://the-guild.dev/graphql/hive/docs/router/configuration/expressions). ## Dynamic Exclusions in Apollo Router As in Hive Router, Apollo Router used to support only operation name based exclusions. With the new dynamic exclusions feature, you can now specify custom logic to exclude requests from usage reporting. # New `add_report_with_request` method in Hive Console SDK In order to support exclusions based on request properties, a new method `add_report_with_request` has been added to the Hive Console SDK. This method allows you to include the request information in the report, which can then be used in the dynamic exclusion logic.
## Fixes ### HTTP/2 Cleartext (h2c) Support for Subgraph Connections Adds support for HTTP/2 cleartext (h2c) connections between the router and subgraphs via the new `allow_only_http2` configuration flag. When enabled, the router uses HTTP/2 prior knowledge to communicate with subgraphs over plain HTTP without TLS. This is useful in environments where subgraphs support HTTP/2 but TLS is not required, such as service meshes, internal networks, or sidecar proxies. ## Configuration The flag can be set globally for all subgraphs or per-subgraph. Per-subgraph settings override the global default. ### Global (all subgraphs) ```yaml traffic_shaping: all: allow_only_http2: true ``` ### Per-subgraph ```yaml traffic_shaping: subgraphs: accounts: allow_only_http2: true ``` The default value is `false`, preserving the existing behavior of using HTTP/1.1 for plain HTTP connections and negotiating HTTP/2 via ALPN for TLS connections.
## Features ### Persisted Documents Introduces persisted documents support in Hive Router with configurable extraction and storage backends. Supports extracting persisted document IDs from: - `documentId` in request body (default) - `documentId` in URL query params (default) - Apollo-style `extensions.persistedQuery.sha256Hash` (default) - custom `json_path` (for example `doc_id` or `extensions.anything.id`) - custom `url_query_param` (for example `?doc_id=123`) - custom `url_path_param` (for example `/graphql/:id`) Order is configurable and evaluated top-to-bottom. Supports persisted document resolution from: - file manifests (Apollo and Relay KV styles) - Hive CDN (via `hive-console-sdk`) File storage includes watch mode by default (with 150ms debounce) to reload manifests after file changes. Hive storage validates document ID syntax before generating CDN paths to avoid silent invalid-path behavior. Adds persisted-documents metrics: - `hive.router.persisted_documents.extract.missing_id_total` - `hive.router.persisted_documents.storage.failures_total` These help track migration progress and resolution failures in production ### TLS Support Adds TLS support to Hive Router for both client and subgraph connections, including mutual TLS (mTLS) authentication. This allows secure communication between clients, the router, and subgraphs by encrypting data in transit and optionally verifying identities. ### TLS Directions TLS Support has implementations for the following 4 directions: #### Router -> Client - Regular TLS Router has an `identity` (`cert`, `key`), and client has `cert`, then Client validates the router's `identity` #### Client -> Router - mTLS Router has the `cert`, client has the `identity`, mTLS/Client Auth then the router validates the client's `identity` #### Subgraph -> Router - Regular TLS Subgraph has the `identity` (`cert`, `key`), and router has `cert`, then Router validates the subgraph's `identity`. #### Router -> Subgraph - mTLS Subgraph has the `cert`, router(which is the client this time) has the `identity`, then subgraph validates the router's `identity`. ### TLS Directions Diagram ```mermaid flowchart LR Client["Client"] Router["Router"] Subgraph["Subgraph"] %% Router -> Client: Regular TLS Router -- "TLS\n(cert_file + key_file)" --> Client Client -. "validates router identity\n(cert_file)" .-> Router %% Client -> Router: mTLS / Client Auth Client -- "mTLS\n(client identity)" --> Router Router -. "validates client identity\n(client_auth.cert_file)" .-> Client %% Subgraph -> Router: Regular TLS Subgraph -- "TLS\n(cert_file)" --> Router Router -. "validates subgraph identity\n(all/subgraphs.cert_file)" .-> Subgraph %% Router -> Subgraph: mTLS Router -- "mTLS\n(client_auth.cert_file + key_file)" --> Subgraph Subgraph -. "validates router identity\n(cert_file)" .-> Router ``` ### Configuration Structure ```yaml traffic_shaping: router: key_file: # Router server private key cert_file: # Router server certificate(s) client_auth: # mTLS: Client -> Router cert_file: # Trusted client CA certificate(s) all: # Default TLS for all subgraph connections cert_file: # Trusted subgraph CA certificate(s) client_auth: # mTLS: Router -> Subgraph cert_file: # Router client certificate(s) key_file: # Router client private key subgraphs: SUBGRAPH_NAME: # Per-subgraph TLS override cert_file: # Trusted subgraph CA certificate(s) client_auth: # mTLS: Router -> Subgraph cert_file: # Router client certificate(s) key_file: # Router client private key ```
## Features ### Federated GraphQL Subscriptions Hive Router now supports federated GraphQL subscriptions with full protocol coverage across [SSE](https://the-guild.dev/graphql/hive/docs/router/subscriptions/sse), [WebSockets](https://the-guild.dev/graphql/hive/docs/router/subscriptions/websockets), [Multipart HTTP](https://the-guild.dev/graphql/hive/docs/router/subscriptions/multipart-http), [Incremental Delivery](https://the-guild.dev/graphql/hive/docs/router/subscriptions/incremental-delivery), and [HTTP Callback](https://the-guild.dev/graphql/hive/docs/router/subscriptions/http-callback) - for both client-to-router and router-to-subgraph communication. Subscription events spanning multiple subgraphs are resolved automatically: when a subscription field lives in one subgraph but the response includes entity fields owned by others, the router fetches those on every event with no extra configuration. - [Read the product update](https://the-guild.dev/graphql/hive/product-updates/2026-04-14-hive-router-subscriptions) - [Subscriptions overview](https://the-guild.dev/graphql/hive/docs/router/subscriptions) - [Server-Sent Events](https://the-guild.dev/graphql/hive/docs/router/subscriptions/sse) - [Incremental Delivery over HTTP](https://the-guild.dev/graphql/hive/docs/router/subscriptions/incremental-delivery) - [Multipart HTTP](https://the-guild.dev/graphql/hive/docs/router/subscriptions/multipart-http) - [WebSockets](https://the-guild.dev/graphql/hive/docs/router/subscriptions/websockets) - [HTTP Callback](https://the-guild.dev/graphql/hive/docs/router/subscriptions/http-callback) ## Fixes ### Query Plan Subscriptions Node The query planner now emits a `Subscription` node when planning a subscription operation. The `Subscription` node contains a `primary` fetch that is sent to the subgraph owning the subscription field.