Working with Router
Configuring GraphOS Router for Apollo Connectors
In this guide, you'll learn how to configure GraphOS Router for Apollo Connectors by configuring connectors
and other options in your router's configuration.
Once you configure it, GraphOS Router enables connectors to orchestrate calls to REST endpoints.
- Just getting start with Apollo Connectors? Try out the quickstart to build your first connector.
- Love developer tooling? Explore Apollo's IDE plugins for GraphQL development, including connectors support.
Configuring router for connectorsSince 2.0.0
Configuring a self-hosted router for connectors requires setting options in the router's YAML configuration file.
When using Rover, you can call rover dev
to start a router locally and use its --router-config
option to pass your configuration file. For example:
APOLLO_KEY=... \
APOLLO_GRAPH_REF=... \
APOLLO_ROVER_DEV_ROUTER_VERSION=2.0.0 \
rover dev --supergraph-config supergraph.yaml
--router-config router.yaml
Connectors configuration are nested under the connectors
key.
Some configurations are applicable globally to all connectors, some are applicable to specific connector sources, and some can be configured for both.
For example, you can apply request limits both globally across all connectors and on specific connector sources.
connectors:
# This applies globally to all connectors
max_requests_per_operation_per_source: 100
# This applies to connectors with the "v1" source in the "example" subgraph
sources:
example.v1:
max_requests_per_operation: 50
To specify a source, you must include the subgraph name and source name, separated by a .
—for example, subgraph_name.connector_name
.
To learn more about other router configurations, go to the router configuration reference.
Request limits
You can configure the maximum number of REST API requests for each GraphQL operation in the router. This can help avoid overwhelming upstream services. For requests that exceed the limit, the router returns a null
value in the GraphQL result for any fields with @connect
directives. Additionally, the router returns a GraphQL error in the errors
array of the response. Partial data may still be returned for portions of the operation that weren't affected by the limit.
You set request limits in the router config YAML:
connectors:
max_requests_per_operation_per_source: 100
This configuration limits the number of requests made to each connector source for a given GraphQL operation. If a connector doesn't define a source, then this limit is applied at the connector level.
The limit can also be configured for each individual connector source:
connectors:
sources:
example.v1:
max_requests_per_operation: 50
Limits set on an individual source override the general max_requests_per_operation_per_source
limit.
The limit can also be configured by setting the environment variable APOLLO_CONNECTORS_MAX_REQUESTS_PER_OPERATION
.
Any configuration in the YAML file overrides the environment variable setting.
Overriding baseURL
for environment-specific API hosts
When using a self-hosted router, the baseURL
of a @source
directive can be overridden in the router configuration file.
For example, by configuring connectors.sources
, you can override the baseURL
for all @connect
directives in the subgraph that reference the v1
source in the example
subgraph.
connectors:
sources:
example.v1:
# These configurations apply to connectors with the "v1" source in the "example" subgraph
override_url: "https://api.example.com/v1/beta"
@connect
directive doesn't specify the source
attribute, its URL can't be overridden.Configuration and environment variables
You may want to use a configuration value or environment variable as part of a request. You can do this per source in the router configuration using the $config
section.
connectors:
sources:
example.v1:
# These configurations apply to connectors with the "v1" source in the "example" subgraph
$config:
my.config.value: true
example.v2:
# These configurations apply to connectors with the "v2" source in the "example" subgraph
$config:
another.config.value: true # Applies to the "v2" source
You can then access the value using the $config
variable in the schema, for example in the URL template or header of a
connector:
type Query {
something: String!
@connect(
http: {
GET: "https://api.example.com/products/{$config.name_of_the_variable}"
headers: [
{
name: "Authorization"
value: "Bearer {$config.name_of_variable_containing_token}"
}
]
}
selection: ""
)
}
You can also access nested values using dot notation. For example $config.nested.value
would refer to:
connectors:
sources:
example.v1:
$config:
nested:
value: "some value"
Router configuration also lets you inject environment variables like this:
connectors:
sources:
example.v1:
$config:
name_of_the_variable: ${env.VARIABLE_NAME}
Telemetry
Router telemetry can be configured for connectors. See the connector troubleshooting guide's debugging section for information on how to add debug information to telemetry.
Attributes
Attributes can be attached to telemetry such as instruments and events. These attributes are used to filter and group data in your application performance monitor (APM).
The following standard attributes are available for connectors:
Attribute | Description |
---|---|
subgraph.name | The name of the subgraph containing the connector |
connector.source.name | The name of the @source associated with this connector, if any |
connector.http.method | The HTTP method for the connector (GET or POST , for example) |
connector.url.template | The URL template for the connector |
Selectors
A selector is used to extract data from connectors requests and responses and attach the data to telemetry such as instruments and events.
Apollo Connectors for REST APIs make HTTP calls to the upstream HTTP API. The selectors in the following table let you extract metrics from these HTTP requests and responses.
Selector | Defaultable | Values | Description |
---|---|---|---|
subgraph_name | No | true |false | The name of the subgraph containing the connector |
connector_source | No | name | The name of the @source associated with this connector, if any |
connector_http_request_header | Yes | The name of a connector request header | |
connector_http_response_header | Yes | The name of a connector response header | |
connector_http_response_status | No | code |reason | The status of a connector response |
connector_http_method | No | true |false | The HTTP method of a connector request |
connector_url_template | No | true |false | The URL template of a connector request |
connector_request_mapping_problems | No | problems |count | Any mapping problems with the connector request |
connector_response_mapping_problems | No | problems |count | Any mapping problems with the connector response |
static | No | A static string value | |
error | No | reason | A string value containing error reason when it's a critical error |
Instruments
An instrument in the router collects data and reports measurements to a metric backend. Supported instruments include standard instruments from OpenTelemetry, standard instruments for the router request lifecycle, and custom instruments. Supported instrument kinds are counters and histograms.
You can configure instruments in router.yaml
with telemetry.instrumentation.instruments
.
OpenTelemetry standard instruments
OpenTelemetry specifies multiple standard metric instruments that are available for connectors HTTP requests and responses:
http.client.request.body.size
- A histogram of request body sizes for connectors HTTP requests.http.client.request.duration
- A histogram of request durations for connectors HTTP requests.http.client.response.body.size
- A histogram of response body sizes for connectors HTTP responses.
These instruments are configurable in router.yaml
:
telemetry:
instrumentation:
instruments:
connector:
http.client.request.body.size: true
http.client.request.duration: true
http.client.response.body.size: true
The default_requirement_level
setting configures whether or not these instruments are enabled by default. They can be customized by attaching or removing attributes. See attributes to learn more about configuring attributes.
telemetry:
instrumentation:
instruments:
connector:
http.client.request.duration:
attributes:
connector.source.name: true
Custom instruments
You can define custom instruments on connectors HTTP requests and responses.
For example, the following custom instrument provides the number of 404 response statuses from a specific REST API:
telemetry:
instrumentation:
instruments:
connector:
acme.user.not.found:
value: unit
type: counter
unit: count
description: "Count of 404 responses from the user API"
condition:
all:
- eq:
- 404
- connector_http_response_status: code
- eq:
- "user_api"
- connector_source: name
See the router documentation for more details about configuring instruments.
Events
An event is used to signal when something of note happens, such as a connector request or response.
You can configure events for each service in router.yaml
. Events can be standard or custom, and they can be triggered by configurable conditions.
See the router documentation for more details about configuring events.
Standard events
Standard events can be configured for connectors. The following enables standard connector HTTP response events at the INFO
level:
events:
connector:
request: off
response: info
error: error
Custom events
Custom events can also be configured for connectors. The following example defines a custom event for each connector HTTP response at the INFO
level:
events:
connector:
connector.response:
message: "Connector response"
level: info
on: response
attributes:
connector.http.method: true
connector.url.template: true
response_status:
connector_http_response_status: code
If you have a stdout
logging exporter, the router logs each connector response with the attributes defined above:
1INFO connector.http.method=GET connector.url.template=/users response_status=200 Connector response kind=connector.response
2INFO connector.http.method=GET connector.url.template=/users/{$this.id}/posts response_status=200 Connector response kind=connector.response
Authentication
Apollo Connectors can be used to call AWS HTTP APIs using AWS Signature Version 4 (SigV4). For example, you can use Apollo Connectors to invoke an AWS Lambda function and select fields from the JSON result to include in your GraphQL response:
@source(
name: "lambda"
http: { baseURL: "https://lambda.us-east-1.amazonaws.com" }
)
...
@connect(
source: "lambda"
http: {
POST: "/2015-03-31/functions/function_name/invocations"
body: "argument: $this.function_argument"
}
selection: "$.function_output"
)
SigV4 authentication is configured separately for each connector source, allowing you to specify a role with the least-privilege necessary to invoke the AWS API for that source:
authentication:
connector:
sources:
subgraph_name.connector_source_name:
aws_sig_v4:
default_chain:
profile_name: "default"
region: "us-east-1"
service_name: "lambda"
assume_role:
role_arn: "arn:aws:iam::XXXXXXXXXXXX:role/lambaexecute"
session_name: "connector"
Authentication with coprocessors
You can use coprocessors to fetch authentication tokens for connectors. This is useful when you need to fetch a token from a different source, such as a database or a third-party service, before making a request to an API.
Start by configuring the coprocessor for the Execution Request stage and enabling the expose_sources_in_context
feature of connectors:
connectors:
expose_sources_in_context: true
coprocessor:
url: http://localhost:4001
execution:
request:
context: true
In the context
of the coprocessor request, you will find a list of subgraph and source names from the query plan. You can use this information to determine which identity providers (IDPs) to query for tokens.
{
"version": 1,
"stage": "ExecutionRequest",
"control": "continue",
"id": "d0a8245df0efe8aa38a80dba1147fb2e",
"context": {
"entries": {
"apollo_connectors::sources_in_query_plan": [
{ "subgraph_name": "products", "source_name": "v1" }
]
}
}
}
In the coprocessor response, you can add the API keys for each source to the context
:
{
"version": 1,
"stage": "ExecutionRequest",
"control": "continue",
"id": "d0a8245df0efe8aa38a80dba1147fb2e",
"context": {
"entries": {
"apollo_connectors::sources_in_query_plan": [
{ "subgraph_name": "products", "source_name": "v1" }
],
"api_keys": {
"products_v1": "abcd1234"
}
}
}
}
Then in the configuration for your connector source, you can use the keys from the context as header values:
extend schema
@source(
name: "v1"
http: {
baseURL: "https://api.example.com/v1"
headers: [
{
name: "Authorization"
value: "Bearer {$context.api_keys.products_v1}"
}
]
}
)
Limitations
See the limitations reference for a list of unsupported router features.