Skip to content

Releases: apollographql/router

v0.14.0

02 Aug 15:10
9c0864c
Compare
Choose a tag to compare

❗ BREAKING ❗

Regex allow_any_origin behavior changed (PR #1444)

Setting allow_any_origin to true in the router configuration would previously automatically mirror the requested headers.
If you relied on this behavior, you now also need to set allow_any_header to true, as explained in the CORS documentation.

server:
  cors:
    allow_any_origin: true
    allow_any_header: true # mirror client's headers

The default CORS headers configuration of the router allows content-type, apollographql-client-version and apollographql-client-name.

By @o0Ignition0o in #1444

Modify the plugin new method to pass an initialisation structure (PR #1446)

This change alters the new method for plugins to pass a PluginInit struct.

We are making this change so that we can pass more information during plugin startup. The first change is that in addition to passing
the plugin configuration, we are now also passing the router supergraph sdl (Schema Definition Language) as a string.

There is a new example (supergraph_sdl) which illustrates how to use this new capability.

By @garypen in #1446

Remove the generic stream type from RouterResponse and ExecutionResponse (PR #1420)

This generic type complicates the API with limited benefit because we use BoxStream everywhere in plugins:

  • RouterResponse<BoxStream<'static, Response>> -> RouterResponse
  • ExecutionResponse<BoxStream<'static, Response>> -> ExecutionResponse

By @Geal in #1420

Remove the HTTP request from QueryPlannerRequest (PR #1439)

The content of QueryPlannerRequest is used as argument to the query planner and as a cache key,
so it should not change depending on the variables or HTTP headers.

By @Geal in #1439

Change PluggableRouterServiceBuilder methods (PR #1437)

with_naive_introspection and with_defer_support where two parameter-less methods
of this builder that enabled boolean configuration flags.
They have been removed and replaced by with_configuration
which takes Arc<apollo_router::Configuration>.
A Configuration value can be created from various formats by deserializing with serde.
The removed methods correspond to server.introspection and server.experimental_defer_support
configuration keys respectively.

By @SimonSapin in #1437

Changes to the SchemaKind enum (PR #1437)

The Instance variant is replaced with a variant named String that contains…
a String instead of Box<apollo_router::Schema>,
so you no longer need to parse the schema before giving it to the router.
Similarly, the Stream variant now contains a stream of Strings
instead of a stream of already-parsed Schemas.

By @SimonSapin in #1437

Schema no longer implements FromStr (PR #1437)

This means that str.parse::<apollo_router::Schema>() is no longer available.
If you still need a parsed Schema (see above),
use apollo_router::Schema(str, &configuration) instead.
To use the default apollo_router::Configuration
you can call apollo_router::Schema(str, &Default::default()).

By @SimonSapin in #1437

🚀 Features

Publish helm chart to OCI registry (PR #1447)

When we make a release, publish our helm chart to the same OCI registry that we use for our docker images.

For more information about using OCI registries with helm, see the helm documentation.

By @garypen in #1447

Configure Regex based CORS rules (PR #1444)

The router now supports regex based CORS rules, as explained in the docs
It also supports the allow_any_header setting that will mirror client's requested headers.

server:
  cors:
    match_origins:
      - "https://([a-z0-9]+[.])*api[.]example[.]com" # any host that uses https and ends with .api.example.com
    allow_any_header: true # mirror client's headers

The default CORS headers configuration of the router allows content-type, apollographql-client-version and apollographql-client-name.

By @o0Ignition0o in #1444

Add support of error section in telemetry to add custom attributes (PR #1443)

The telemetry is now able to hook at the error stage if router or a subgraph is returning an error. Here is an example of configuration:

telemetry:
  metrics:
    prometheus:
      enabled: true
    common:
      attributes:
        subgraph:
          all:
            errors: # Only works if it's a valid GraphQL error
              include_messages: true # Will include the error message in a message attribute
              extensions: # Include extension data
                - name: subgraph_error_extended_type # Name of the attribute
                  path: .type # JSON query path to fetch data from extensions

By @bnjjj in #1443

Experimental support for the @defer directive (PR #1182)

The router can now understand the @defer directive, used to tag parts of a query so the response is split into
multiple parts that are sent one by one.

⚠️ this is still experimental and not fit for production use yet

To activate it, add this option to the configuration file:

server:
  experimental_defer_support: true

By @Geal in #1182

Rewrite the caching API (PR #1281)

This introduces a new asynchronous caching API that opens the way to multi level caching (in memory and
database). The API revolves around an Entry structure that allows query deduplication and lets the
client decide how to generate the value to cache, instead of a complicated delegate system inside the
cache.

By @Geal in #1281

🐛 Fixes

Update serialization format for telemetry.tracing.otlp.grpc.metadata (PR #1391)

The metadata format now uses IndexMap<String, Vec<String>>.

By @me-diru in #1391

Update the scaffold template so it targets router v0.14.0 (PR #1431)

The cargo scaffold template will target the latest version of the router.

By @o0Ignition0o in #1248

Selection merging on non-object field aliases (PR #1406)

Fixed a bug where merging aliased fields would sometimes put nulls instead of expected values.

By @o0Ignition0o in #1432

A Rhai error instead of a Rust panic ([PR #1414 https://github.com//pull/1414))

In Rhai plugins, accessors that mutate the originating request are not available when in the subgraph phase. Previously, trying to mutate anyway would cause a Rust panic. This has been changed to a Rhai error instead.

By @SimonSapin in #1414

Optimizations (PR #1423)

  • Do not clone the client request during query plan execution
  • Do not clone the usage reporting
  • Avoid path allocations when iterating over JSON values

The benchmarks show that this change brings a 23% gain in requests per second compared to the main branch.

By @Geal in #1423

do not perform nested fetches if the parent one returned null (PR #1332

In a query of the form:

mutation {
	mutationA {
		mutationB
	}
}

If mutationA returned null, we should not execute mutationB.

By @Ty3uK in #1332

🛠 Maintenance

📚 Documentation

Updates wording and formatting of README.md

By @EverlastingBugstopper in #1445

What's Changed

Read more

v0.12.1-alpha-defer4

22 Jul 15:00
Compare
Choose a tag to compare
v0.12.1-alpha-defer4 Pre-release
Pre-release

⚠️ This is a test release, not meant for general use

How to test @defer support in the router
Add this to the configuration file:

server:
  experimental_defer_support: true

v0.12.1-alpha-defer3

21 Jul 17:22
Compare
Choose a tag to compare
v0.12.1-alpha-defer3 Pre-release
Pre-release

⚠️ This is a test release, not meant for general use

How to test @defer support in the router
Add this to the configuration file:

server:
  experimental_defer_support: true

Add this to the supergraph schema:

directive @defer(
  label: String
  if: Boolean
) on FRAGMENT_SPREAD | INLINE_FRAGMENT

v0.12.1-alpha-defer2

20 Jul 14:22
Compare
Choose a tag to compare
v0.12.1-alpha-defer2 Pre-release
Pre-release

⚠️ this is a test release, not meant for general use

v0.12.1-alpha-defer

19 Jul 14:10
Compare
Choose a tag to compare
v0.12.1-alpha-defer Pre-release
Pre-release

⚠️ this is a test release, not meant for general use

v0.12.0

18 Jul 16:29
879d421
Compare
Choose a tag to compare

[0.12.0] - 2022-08-18

❗ BREAKING ❗

Move experimental.rhai out of experimental PR #1365

You will need to update your YAML configuration file to use the correct name for rhai plugin.

- plugins:
-   experimental.rhai:
-     filename: /path/to/myfile.rhai
+ rhai:
+   scripts: /path/to/directory/containing/all/my/rhai/scripts (./scripts by default)
+   main: <name of main script to execute> (main.rhai by default)

You can now modularise your rhai code. Rather than specifying a path to a filename containing your rhai code, the rhai plugin will now attempt to execute the script specified via main. If modules are imported, the rhai plugin will search for those modules in the scripts directory. for more details about how rhai makes use of modules, look at the rhai documentation.

The simplest migration will be to set scripts to the directory containing your myfile.rhai and to rename your myfile.rhai to main.rhai.

By @garypen in #1365

🐛 Fixes

The opentelemetry-otlp crate needs a http-client feature PR #1392

The opentelemetry-otlp crate only checks at runtime if a HTTP client was added through
cargo features. We now use reqwest for that.

By @geal in #1392

Expose the custom endpoints from RouterServiceFactory (PR #1402)

Plugin HTTP endpoints registration was broken during the Tower refactoring. We now make sure that the list
of endpoints is generated from the RouterServiceFactory instance.

By @geal in #1402

🛠 Maintenance

Dependency updates PR #1389 PR #1394 PR #1395

Dependency updates were blocked for some time due to incompatibilities:

  • #1389: the router-bridge crate needed a new version of deno_core in its workspace that would not fix the version of once_cell. Now that it is done we can update once_cell in the router
  • #1395: clap at version 3.2 changed the way values are extracted from matched arguments, which resulted in panics. This is now fixed and we can update clap in the router and related crates
  • #1394: broader dependency updates now that everything is locked
  • #1410: revert tracing update that caused two telemetry tests to fail (the router binary is not affected)

By @Geal in #1389 #1394 #1395 and @o0Ignition0o in #1410

v0.11.0

12 Jul 13:25
8d5344f
Compare
Choose a tag to compare

❗ BREAKING ❗

Relax plugin api mutability PR #1340 PR #1289

the Plugin::*_service() methods were taking a &mut self as argument, but since
they work like a tower Layer, they can use &self instead. This change
then allows us to move from Buffer to service factories for the query
planner, execution and subgraph services.

Services are now created on the fly at session creation, so if any state must be shared
between executions, it should be stored in an Arc<Mutex<_>> in the plugin and cloned
into the new service in the Plugin::*_service() methods
.

By @Geal in #1340 #1289

🚀 Features

Add support to add custom resources on metrics. PR #1354

Resources are almost like attributes but more global. They are directly configured on the metrics exporter which means you'll always have these resources on each of your metrics. This functionality can be used to, for example,
apply a service.name to metrics to make them easier to find in larger infrastructure, as demonstrated here:

telemetry:
  metrics:
    common:
      resources:
        # Set the service name to easily find metrics related to the apollo-router in your metrics dashboards
        service.name: "apollo-router"

By @bnjjj in #1354

🐛 Fixes

Fix fragment on interface without typename PR #1371

When the subgraph doesn't return the __typename and the type condition of a fragment is an interface, we should return the values if the entity implements the interface

By @bnjjj in #1371

Fix detection of an introspection query PR #1370

A query that only contains __typename at the root will now special-cased as merely an introspection query and will bypass more complex query-planner execution (its value will just be Query).

By @bnjjj in #1370

Accept nullable list as input PR #1363

Do not throw a validation error when you give null for an input variable of type [Int!].

By @bnjjj in #1363

🛠 Maintenance

Replace Buffers of tower services with service factories (PR #1289 PR #1355)

Tower services should be used by creating a new service instance for each new session
instead of going through a Buffer.

By @Geal in #1289 #1355

Execute the query plan's first response directly (PR #1357)

The query plan was previously executed in a spawned task to prepare for the @defer implementation, but we can actually
generate the first response right inside the same future.

By @Geal in #1357

Remove deprecated failure crate from the dependency tree PR #1373

This should fix automated reports about GHSA-jq66-xh47-j9f3.

By @yanns in #1373

Render embedded Sandbox instead of landing page (PR #1369)

Open the router URL in a browser and start querying the router from the Apollo Sandbox.

By @mayakoneval in #1369

📚 Documentation

Various documentation edits (PR #1329)

By @StephenBarlow in #1329

v0.10.0

05 Jul 14:45
c66dc31
Compare
Choose a tag to compare

❗ 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 impr...

Read more

v0.9.5

17 Jun 13:49
947adc6
Compare
Choose a tag to compare

❗ BREAKING ❗

Move experimental.traffic_shaping out of experimental PR #1229

You will need to update your YAML configuration file to use the correct name for traffic_shaping plugin.

- plugins:
-   experimental.traffic_shaping:
-     variables_deduplication: true # Enable the variables deduplication optimization
-     all:
-       query_deduplication: true # Enable query deduplication for all subgraphs.
-     subgraphs:
-       products:
-         query_deduplication: false # Disable query deduplication for products.
+ traffic_shaping:
+   variables_deduplication: true # Enable the variables deduplication optimization
+   all:
+     query_deduplication: true # Enable query deduplication for all subgraphs.
+   subgraphs:
+     products:
+       query_deduplication: false # Disable query deduplication for products.

Rhai plugin request.sub_headers renamed to request.subgraph.headers PR #1261

Rhai scripts previously supported the request.sub_headers attribute so that subgraph request headers could be
accessed. This is now replaced with an extended interface for subgraph requests:

request.subgraph.headers
request.subgraph.body.query
request.subgraph.body.operation_name
request.subgraph.body.variables
request.subgraph.body.extensions
request.subgraph.uri.host
request.subgraph.uri.path

By @garypen in #1261

🚀 Features

Add support of compression PR #1229

Add support of request and response compression for the router and all subgraphs. The router is now able to handle Content-Encoding and Accept-Encoding headers properly. Supported algorithms are gzip, br, deflate.
You can also enable compression on subgraphs requests and responses by updating the traffic_shaping configuration:

traffic_shaping:
  all:
    compression: br # Enable brotli compression for all subgraphs
  subgraphs:
    products:
      compression: gzip # Enable gzip compression only for subgraph products

By @bnjjj in #1229

Add support of multiple uplink URLs PR #1210

Add support of multiple uplink URLs with a comma-separated list in APOLLO_UPLINK_ENDPOINTS and for --apollo-uplink-endpoints

Example:

export APOLLO_UPLINK_ENDPOINTS="https://aws.uplink.api.apollographql.com/, https://uplink.api.apollographql.com/"

By @bnjjj in #1210

Add support for adding extra environment variables and volumes to helm chart PR #1245

You can mount your supergraph.yaml into the helm deployment via configmap. Using Kustomize to generate your configmap from your supergraph.yaml is suggested.

Example configmap.yaml snippet:

supergraph.yaml:
    server:
        listen: 0.0.0.0:80

Example helm config:

extraEnvVars:
  - name: APOLLO_ROUTER_SUPERGRAPH_PATH
    value: /etc/apollo/supergraph.yaml
    # sets router log level to debug
  - name: APOLLO_ROUTER_LOG
    value: debug
extraEnvVarsCM: ''
extraEnvVarsSecret: ''

extraVolumes:
  - name: supergraph-volume
    configMap:
      name: some-configmap 
extraVolumeMounts: 
  - name: supergraph-volume
    mountPath: /etc/apollo

By @LockedThread in #1245

🐛 Fixes

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 that 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 has been updated so that it generates plugins that are compatible with the new Plugin API.

By @o0Ignition0o in #1248

Create the ExecutionResponse after the primary response was generated (PR #1260)

The @defer preliminary work had a surprising side effect: when using methods like RouterResponse::map_response, they were
executed before the subgraph responses were received, because they work on the stream of responses.
This PR goes back to the previous behaviour by awaiting the primary response before creating the ExecutionResponse.

By @Geal in #1260

Use the API schema to generate selections (PR #1255)

When parsing the schema to generate selections for response formatting, we should use the API schema instead of the supergraph schema.

By @Geal in #1255

📚 Documentation

Update README link to the configuration file (PR #1208)

As the structure of the documentation has changed, the link should point to the YAML config file section of the overview.

By [@gscheibel](https://github.com/gscheibel in #1208

v0.9.4

14 Jun 12:59
0387f9b
Compare
Choose a tag to compare

❗ BREAKING ❗

Groundwork for @defer support (PR #1175, PR #1206)

To prepare for the implementation of the @defer directive, the ExecutionResponse and RouterResponse types now carry a stream of responses instead of a unique response. For now that stream contains only one item, so there is no change in behaviour. However, the Plugin trait changed to accomodate this, so a couple of steps are required to migrate your plugin so it is compatible with router v0.9.4:

  • Add a dependency to futures in your Cargo.toml:
+futures = "0.3.21"
  • Import BoxStream, and if your Plugin defines a router_service behavior, import ResponseBody:
+ use futures::stream::BoxStream;
+ use apollo_router::ResponseBody;
  • Update the router_service and the execution_service sections of your Plugin (if applicable):
      fn router_service(
         &mut self,
-        service: BoxService<RouterRequest, RouterResponse, BoxError>,
-    ) -> BoxService<RouterRequest, RouterResponse, BoxError> {
+        service: BoxService<RouterRequest, RouterResponse<BoxStream<'static, ResponseBody>>, BoxError>,
+    ) -> BoxService<RouterRequest, RouterResponse<BoxStream<'static, ResponseBody>>, BoxError> {

[...]

     fn execution_service(
         &mut self,
-        service: BoxService<ExecutionRequest, ExecutionResponse, BoxError>,
-    ) -> BoxService<ExecutionRequest, ExecutionResponse, BoxError> {
+        service: BoxService<ExecutionRequest, ExecutionResponse<BoxStream<'static, Response>>, BoxError>,
+    ) -> BoxService<ExecutionRequest, ExecutionResponse<BoxStream<'static, Response>>, BoxError> {

We can now update our unit tests so they work on a stream of responses instead of a single one:

         // Send a request
-        let result = test_harness.call_canned().await?;
-        if let ResponseBody::GraphQL(graphql) = result.response.body() {
+        let mut result = test_harness.call_canned().await?;
+
+        let first_response = result
+            .next_response()
+            .await
+            .expect("couldn't get primary response");
+
+        if let ResponseBody::GraphQL(graphql) = first_response {
             assert!(graphql.data.is_some());
         } else {
             panic!("expected graphql response")
         }

+        // You could keep calling result.next_response() until it yields None if you are expexting more parts.
+        assert!(result.next_response().await.is_none());
         Ok(())
     }

The apollo-router-core crate has been merged into apollo-router (PR #1189)

To upgrade, remove any dependency on the apollo-router-core crate from your Cargo.toml files and change imports like so:

- use apollo_router_core::prelude::*;
+ use apollo_router::prelude::*;

By @SimonSapin in #1189

Fix input validation rules (PR #1211)

The GraphQL specification provides two sets of coercion / validation rules, depending on whether we're dealing with inputs or outputs.
We have added validation rules for specified input validations which were not previously implemented.
This is a breaking change since slightly invalid input may have validated before but will now be guarded by newly-introduced validation rules.

By @o0Ignition0o in #1211

🚀 Features

Add trace logs for parsing recursion consumption (PR #1222)

The apollo-parser package now implements recursion limits which can be examined after the parsing phase. The router logs these
out at trace level. You can see them in your logs by searching for "recursion_limit". For example, when using JSON logging
and using jq to filter the output:

router -s ../graphql/supergraph.graphql -c ./router.yaml --log trace | jq -c '. | select(.fields.message == "recursion limit data")'
{"timestamp":"2022-06-10T15:01:02.213447Z","level":"TRACE","fields":{"message":"recursion limit data","recursion_limit":"recursion limit: 4096, high: 0"},"target":"apollo_router::spec::schema"}
{"timestamp":"2022-06-10T15:01:02.261092Z","level":"TRACE","fields":{"message":"recursion limit data","recursion_limit":"recursion limit: 4096, high: 0"},"target":"apollo_router::spec::schema"}
{"timestamp":"2022-06-10T15:01:07.642977Z","level":"TRACE","fields":{"message":"recursion limit data","recursion_limit":"recursion limit: 4096, high: 4"},"target":"apollo_router::spec::query"}

This example output shows that the maximum recursion limit is 4096 and that the query we processed caused us to recurse 4 times.

By @garypen in #1222

Helm chart now has the option to use an existing secrets for API key (PR #1196)

This change allows the use of an already existing secret for the graph API key.

To use existing secrets, update your own values.yaml file or specify the value on your helm install command line. For example:

helm install --set router.managedFederation.existingSecret="my-secret-name" <etc...>`

By @pellizzetti in #1196

Add iterators to Context (PR #1202)

Context can now be iterated over, with two new methods:

  • iter()
  • iter_mut()

These implementations lean heavily on an underlying DashMap implemetation, so refer to its documentation for more usage details.

By @garypen in #1202

Add an experimental optimization to deduplicate variables in query planner (PR #872)

Get rid of duplicated variables in requests and responses of the query planner. This optimization is disabled by default, if you want to enable it you just need override your configuration:

plugins:
  experimental.traffic_shaping:
    variables_deduplication: true # Enable the variables deduplication optimization

By @bnjjj in #872

Add more customizable metrics (PR #1159)

Added the ability to apply custom attributes/labels to metrics which are derived from header values using the Router's configuration file. For example:

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"

By @bnjjj in #1159

Allow to set a custom health check path (PR #1164)

Added the possibility to set a custom health check path

server:
  # Default is /.well-known/apollo/server-health
  health_check_path: /health

By @jcaromiq in #1164

🐛 Fixes

Pin clap dependency in Cargo.toml (PR #1232)

A minor release of Clap occured yesterday which introduced a breaking change. This change might lead cargo scaffold users to hit a panic a runtime when the router tries to parse environment variables and arguments.

This patch pins the clap dependency to the version that was available before the release, until the root cause is found and fixed upstream.

By @o0Ignition0o in #1232

Display better error message when on subgraph fetch errors (PR #1201)

Show a helpful error message when a subgraph does not return JSON or a bad status code

By @bnjjj in #1201

Fix CORS configuration to eliminate runtime panic on misconfiguration (PR #1197)

Previously, it was possible to specify a CORS configuration which was syntactically valid, but which could not be enforced at runtime. For example, consider the following invalid configuration where the allow_any_origin and allow_credentials parameters are inherantly incompatible with each other (per the CORS specification):

server:
  cors:
    allow_any_origin: true
    allow_credentials: true

Previously, this would result in a runtime panic. The router will now detect this kind of misconfiguration and report the error without panicking.

By @garypen in #1197

🛠 Maintenance

Groundwork for @defer support (PR #1175PR #1206)

To prepare for the implementation of the @defer directive, the ExecutionResponse and RouterResponse types now carry a stream of responses instead of a unique response. For now that stream contains only one item, so there is no change in behaviour.

By @Geal in #1206

Fix a flappy test to test custom health check path (PR #1176)

Force the cre...

Read more