github apollographql/router v0.10.0

latest releases: v1.56.0-rc.0, v1.52.2-rc.0, v1.55.1-rc.1...
2 years ago

[0.10.0] - 2022-07-05

❗ BREAKING ❗

Change configuration for custom attributes for metrics in telemetry plugin (PR #1300

To create a distinction between subgraph metrics and router metrics, a distiction has been made in the configuration. Therefore, a new configuration section called router has been introduced and Router-specific properties are now listed there, as seen here:

telemetry:
  metrics:
    common:
      attributes:
-        static:
-          - name: "version"
-            value: "v1.0.0"
-        from_headers:
-          - named: "content-type"
-            rename: "payload_type"
-            default: "application/json"
-          - named: "x-custom-header-to-add"
+        router:
+          static:
+            - name: "version"
+              value: "v1.0.0"
+          request:
+            header:
+              - named: "content-type"
+                rename: "payload_type"
+                default: "application/json"
+              - named: "x-custom-header-to-add"

By @bnjjj in #1300

Rename http_compat to http_ext (PR #1291

The module provides extensions to the http crate which are specific to the way we use that crate in the router. This change also cleans up the provided extensions and fixes a few potential sources of error (by removing them)
such as the Request::mock() function.

By @garypen in #1291

Rework the entire public API structure (PR #1216, PR #1242, PR #1267, PR #1277, PR #1303)

  • Many items have been removed from the public API and made private.
    If you were relying on these previously-public methods and find that they are no longer available, please open an issue with your use case so we can consider how we want to re-introduce them.

  • Many re-exports have been removed.
    Most notably from the crate root and all of the prelude modules.
    These items now need to be imported from another location instead,
    most often the module that defines them.

  • Some items have moved and need to be imported from a new location.

For example, here are the changes made to examples/add-timestamp-header/src/main.rs:

-use apollo_router::{plugin::utils, Plugin, RouterRequest, RouterResponse};
+use apollo_router::plugin::test;
+use apollo_router::plugin::Plugin;
+use apollo_router::services::{RouterRequest, RouterResponse};
-let mut mock = utils::test::MockRouterService::new();
+let mut mock = test::MockRouterService::new();
-if let apollo_router::ResponseBody::GraphQL(response) =
+if let apollo_router::services::ResponseBody::GraphQL(response) =
     service_response.next_response().await.unwrap()
 {

If you're unsure where a given item needs to be imported from when porting code,
unfold the listing below and use your browser's search function (CTRL+F or ⌘+F).

Output of ./scripts/public_items.sh for 0.10.0
use apollo_router::ApolloRouter;
use apollo_router::Configuration;
use apollo_router::ConfigurationKind;
use apollo_router::Context;
use apollo_router::Error;
use apollo_router::Executable;
use apollo_router::Request;
use apollo_router::Response;
use apollo_router::Schema;
use apollo_router::SchemaKind;
use apollo_router::ShutdownKind;
use apollo_router::error::CacheResolverError;
use apollo_router::error::FetchError;
use apollo_router::error::JsonExtError;
use apollo_router::error::Location;
use apollo_router::error::ParseErrors;
use apollo_router::error::PlannerErrors;
use apollo_router::error::QueryPlannerError;
use apollo_router::error::SchemaError;
use apollo_router::error::ServiceBuildError;
use apollo_router::error::SpecError;
use apollo_router::graphql::Error;
use apollo_router::graphql::NewErrorBuilder;
use apollo_router::graphql::Request;
use apollo_router::graphql::Response;
use apollo_router::json_ext::Object;
use apollo_router::json_ext::Path;
use apollo_router::json_ext::PathElement;
use apollo_router::layers::ServiceBuilderExt;
use apollo_router::layers::ServiceExt;
use apollo_router::layers::async_checkpoint::AsyncCheckpointLayer;
use apollo_router::layers::async_checkpoint::AsyncCheckpointService;
use apollo_router::layers::cache::CachingLayer;
use apollo_router::layers::cache::CachingService;
use apollo_router::layers::instrument::InstrumentLayer;
use apollo_router::layers::instrument::InstrumentService;
use apollo_router::layers::map_future_with_context::MapFutureWithContextLayer;
use apollo_router::layers::map_future_with_context::MapFutureWithContextService;
use apollo_router::layers::sync_checkpoint::CheckpointLayer;
use apollo_router::layers::sync_checkpoint::CheckpointService;
use apollo_router::main;
use apollo_router::mock_service;
use apollo_router::plugin::DynPlugin;
use apollo_router::plugin::Handler;
use apollo_router::plugin::Plugin;
use apollo_router::plugin::PluginFactory;
use apollo_router::plugin::plugins;
use apollo_router::plugin::register_plugin;
use apollo_router::plugin::serde::deserialize_header_name;
use apollo_router::plugin::serde::deserialize_header_value;
use apollo_router::plugin::serde::deserialize_option_header_name;
use apollo_router::plugin::serde::deserialize_option_header_value;
use apollo_router::plugin::serde::deserialize_regex;
use apollo_router::plugin::test::IntoSchema;
use apollo_router::plugin::test::MockExecutionService;
use apollo_router::plugin::test::MockQueryPlanningService;
use apollo_router::plugin::test::MockRouterService;
use apollo_router::plugin::test::MockSubgraph;
use apollo_router::plugin::test::MockSubgraphService;
use apollo_router::plugin::test::NewPluginTestHarnessBuilder;
use apollo_router::plugin::test::PluginTestHarness;
use apollo_router::plugins::csrf::CSRFConfig;
use apollo_router::plugins::csrf::Csrf;
use apollo_router::plugins::rhai::Conf;
use apollo_router::plugins::rhai::Rhai;
use apollo_router::plugins::telemetry::ROUTER_SPAN_NAME;
use apollo_router::plugins::telemetry::Telemetry;
use apollo_router::plugins::telemetry::apollo::Config;
use apollo_router::plugins::telemetry::config::AttributeArray;
use apollo_router::plugins::telemetry::config::AttributeValue;
use apollo_router::plugins::telemetry::config::Conf;
use apollo_router::plugins::telemetry::config::GenericWith;
use apollo_router::plugins::telemetry::config::Metrics;
use apollo_router::plugins::telemetry::config::MetricsCommon;
use apollo_router::plugins::telemetry::config::Propagation;
use apollo_router::plugins::telemetry::config::Sampler;
use apollo_router::plugins::telemetry::config::SamplerOption;
use apollo_router::plugins::telemetry::config::Trace;
use apollo_router::plugins::telemetry::config::Tracing;
use apollo_router::query_planner::OperationKind;
use apollo_router::query_planner::QueryPlan;
use apollo_router::query_planner::QueryPlanOptions;
use apollo_router::register_plugin;
use apollo_router::services::ErrorNewExecutionResponseBuilder;
use apollo_router::services::ErrorNewQueryPlannerResponseBuilder;
use apollo_router::services::ErrorNewRouterResponseBuilder;
use apollo_router::services::ErrorNewSubgraphResponseBuilder;
use apollo_router::services::ExecutionRequest;
use apollo_router::services::ExecutionResponse;
use apollo_router::services::ExecutionService;
use apollo_router::services::FakeNewExecutionRequestBuilder;
use apollo_router::services::FakeNewExecutionResponseBuilder;
use apollo_router::services::FakeNewRouterRequestBuilder;
use apollo_router::services::FakeNewRouterResponseBuilder;
use apollo_router::services::FakeNewSubgraphRequestBuilder;
use apollo_router::services::FakeNewSubgraphResponseBuilder;
use apollo_router::services::NewExecutionRequestBuilder;
use apollo_router::services::NewExecutionResponseBuilder;
use apollo_router::services::NewExecutionServiceBuilder;
use apollo_router::services::NewQueryPlannerRequestBuilder;
use apollo_router::services::NewQueryPlannerResponseBuilder;
use apollo_router::services::NewRouterRequestBuilder;
use apollo_router::services::NewRouterResponseBuilder;
use apollo_router::services::NewRouterServiceBuilder;
use apollo_router::services::NewSubgraphRequestBuilder;
use apollo_router::services::NewSubgraphResponseBuilder;
use apollo_router::services::PluggableRouterServiceBuilder;
use apollo_router::services::QueryPlannerContent;
use apollo_router::services::QueryPlannerRequest;
use apollo_router::services::QueryPlannerResponse;
use apollo_router::services::ResponseBody;
use apollo_router::services::RouterRequest;
use apollo_router::services::RouterResponse;
use apollo_router::services::RouterService;
use apollo_router::services::SubgraphRequest;
use apollo_router::services::SubgraphResponse;
use apollo_router::services::SubgraphService;
use apollo_router::services::http_ext::FakeNewRequestBuilder;
use apollo_router::services::http_ext::IntoHeaderName;
use apollo_router::services::http_ext::IntoHeaderValue;
use apollo_router::services::http_ext::NewRequestBuilder;
use apollo_router::services::http_ext::Request;
use apollo_router::services::http_ext::Response;
use apollo_router::subscriber::RouterSubscriber;
use apollo_router::subscriber::is_global_subscriber_set;
use apollo_router::subscriber::replace_layer;
use apollo_router::subscriber::set_global_subscriber;

By @SimonSapin

Entry point improvements (PR #1227) (PR #1234) (PR #1239) (PR #1263)

The interfaces around the entry point have been improved for naming consistency and to enable reuse when customization is required.
Most users will continue to use:

apollo_router::main()

However, if you want to specify extra customization to configuration/schema/shutdown then you may use Executable::builder() to override behavior.

use apollo_router::Executable;
Executable::builder()
  .router_builder_fn(|configuration, schema| ...) // Optional
  .start().await?

Migration tips:

  • Calls to ApolloRouterBuilder::default() should be migrated to ApolloRouter::builder.
  • FederatedServerHandle has been renamed to ApolloRouterHandle.
  • The ability to supply your own RouterServiceFactory has been removed.
  • StateListener. This made the internal state machine unnecessarily complex. listen_address() remains on ApolloRouterHandle.
  • FederatedServerHandle::shutdown() has been removed. Instead, dropping ApolloRouterHandle will cause the router to shutdown.
  • FederatedServerHandle::ready() has been renamed to FederatedServerHandle::listen_address(), it will return the address when the router is ready to serve requests.
  • FederatedServerError has been renamed to ApolloRouterError.
  • main_rt should be migrated to Executable::builder()

By @bryncooke in #1227 #1234 #1239 #1263

Non-GraphQL response body variants removed from RouterResponse (PR #1307, PR #1328)

The ResponseBody enum has been removed.
It had variants for GraphQL and non-GraphQL responses.

It was used:

  • In RouterResponse which now uses apollo_router::graphql::Response instead
  • In Handler for plugin custom endpoints which now uses bytes::Bytes instead

Various type signatures will need changes such as:

- RouterResponse<BoxStream<'static, ResponseBody>>
+ RouterResponse<BoxStream<'static, graphql::Response>>

Necessary code changes might look like:

- return ResponseBody::GraphQL(response);
+ return response;
- if let ResponseBody::GraphQL(graphql_response) = res {
-     assert_eq!(&graphql_response.errors[0], expected_error);
- } else {
-     panic!("expected a graphql response");
- }
+ assert_eq!(&res.errors[0], expected_error);

By @SimonSapin

Fixed control flow in helm chart for volume mounts & environment variables (PR #1283)

You will now be able to actually use the helm chart without being on a managed graph.

By @LockedThread in #1283

Fail when unknown fields are encountered in configuration PR #1278

Now if you add an unknown configuration field at the root of your configuration file it will return an error, rather than silently continuing with un-recognized options.

By @bnjjj in #1278

🚀 Features

Allow custom subgraph-specific attributes to be added to emitted metrics PR #1300

Previously, it was only possible to add custom attributes from headers which the router received from the external GraphQL client. Now, you are able to add custom attributes coming from both the headers and the body of either the Router's or the Subgraph's router request or response. You also have the ability to add an attributes from the context. For example:

telemetry:
  metrics:
    common:
      attributes:
        router:
          static:
            - name: "version"
              value: "v1.0.0"
          request:
            header:
              - named: "content-type"
                rename: "payload_type"
                default: "application/json"
              - named: "x-custom-header-to-add"
          response:
            body:
              # Take element from the Router's JSON response body router located at a specific path
              - path: .errors[0].extensions.status
                name: error_from_body
          context:
            # Take element from the context within plugin chains and add it in attributes
            - named: my_key
        subgraph:
          all:
            static:
              # Always insert this static value on all metrics for ALL Subgraphs
              - name: kind
                value: subgraph_request
          subgraphs:
            # Apply these only for the SPECIFIC subgraph named `my_subgraph_name`
            my_subgraph_name:
              request:
                header:
                  - named: "x-custom-header"
                body:
                  # Take element from the request body of the router located at this path (here it's the query)
                  - path: .query
                    name: query
                    default: UNKNOWN

By @bnjjj in #1300

Add support for modifying variables from a plugin PR #1257

Previously, it was not possible to modify variables in a Request from a plugin. This is now supported via both Rust and Rhai plugins.

By @garypen in #1257

🐛 Fixes

Extend fix for compression support to include the DIY Dockerfiles (PR #1352)

Compression support is now shown in the DIY Dockerfiles, as a followup to PR #1279.

By @garypen in #1352

Improve URL parsing in endpoint configuration (PR #1341)

Specifying an endpoint in this form '127.0.0.1:431' resulted in an error: 'relative URL without a base'. The fix enhances the URL parsing logic to check for these errors and re-parses with a default scheme 'http://' so that parsing succeeds.

By @garypen in #1341

Improve configuration validation and environment expansion (PR #1331)

Environment expansion now covers the entire configuration file, and supports non-string types.

This means that it is now possible to use environment variables in the server section of the YAML configuration, including numeric and boolean fields.

Environment variables will always be shown in their original form within error messages to prevent leakage of secrets.

These changes allow more of the configuration file to be validated via JSON-schema, as previously we just skipped errors where fields contained environment variables.

By @bryncooke in #1331

Fix input coercion for a list (PR #1327)

The router is now following coercion rules for lists in accordance with the GraphQL specification. In particular, this fixes the case when an input type of [Int] with only 1 provided as a value will now be properly coerced to [1].

By @bnjjj in #1327

Returns HTTP 400 Bad Request, rather than a 500, when hitting a query planning error (PR #1321)

A query planning error cannot be retried, so this error code more correctly matches the failure mode and indicates to the client that it should not be retried without changing the request.

By @bnjjj in #1321

Re-enable the subgraph error-redaction functionality (PR #1317)

In a re-factoring the include_subgraph_errors plugin was disabled. This meant that subgraph error handling was not working as intended. This change re-enables it and improves the functionality with additional logging. As part of the fix, the plugin initialization mechanism was improved to ensure that plugins start in the required sequence.

By @garypen in #1317

Restrict static introspection to only __schema and __type (PR #1299)

Queries with selected field names starting with __ are recognized as introspection queries. This includes __schema, __type and __typename. However, __typename is introspection at query time which is different from __schema and __type because two of the later can be answered with queries with empty input variables. This change will restrict introspection to only __schema and __type.

By @dingxiangfei2009 in #1299

Fix plugin scaffolding support (PR #1293)

By @garypen in #1293

Support introspection object types (PR #1240)

Introspection queries can use a set of object types defined in the specification. The query parsing code was not recognizing them, resulting in some introspection queries not working.

By @Geal in #1240

Update the scaffold template so it works with streams (#1247)

Release v0.9.4 changed the way we deal with Response objects, which can now be streams. The scaffold template now generates plugins that are compatible with this new Plugin API.

By @o0Ignition0o in #1248

Fix fragment selection on interfaces (PR #1295)

Fragments type conditions were not being checked correctly on interfaces, resulting in invalid null fields added to the response or valid data being incorrectly null-ified.

By @Geal in #1295

Fix fragment selection on queries (PR #1296)

The schema object can specify objects for queries, mutations or subscriptions that are not named Query, Mutation or Subscription. Response formatting now supports it.

By @Geal in #1296

Fix fragment selection on unions (PR #1346)

Fragments type conditions were not checked correctly on unions, resulting in data being absent.

By @Geal in #1346

Reduce poll_ready calls in query deduplication (PR #1350)

The query deduplication service was making assumptions on the underlying service's behaviour, which could result in subgraph services panicking.

By @Geal in #1350

🛠 Maintenance

chore: Run scaffold tests in CI and xtask only (PR #1345)

Run the scaffold tests in CI and through xtask, to keep a steady feedback loop while developping against cargo test.

By @o0Ignition0o in #1345

Update rhai to latest release (1.8.0) (PR #1337

We had been depending on a pinned git version which had a fix we required. This now updates to the latest release which includes the fix upstream.

By @garypen in #1337

Remove typed-builder (PR #1218)

Migrate all typed-builders code to buildstructor.

By @bryncooke in #1218

Don't miss a new router release

NewReleases is sending notifications on new releases.