Apollo Connectors Preview Features


Want to try out the latest and greatest features of Apollo Connectors? You're in the right place!

Before you jump in, there are a couple important pieces of information:

  1. All of these features are subject to change, use care when updating composition or GraphOS Router.

  2. Make sure to tell us what you think before these features are stable!

Enabling Preview Features

  1. Use GraphOS Router 2.2.0-rc.0 or greater

  2. Configure the router to allow the preview version of connectors:

YAML
1connectors:
2    preview_connect_v0_2: true
  1. Use composition 2.11.0-preview.1 or greater with rover and the "Federation Next" build pipeline in Studio.

  2. Update the schema to use the preview version of connectors.

GraphQL
1extend schema
2  @link(
3    url: "https://specs.apollo.dev/connect/v0.2"
4    import: ["@source", "@connect"]
5  )

The order of these steps matters! Older versions of router will not accept the configuration setting, and routers without the configuration will reject schemas composed with the latest composition version.

@connect on types

You can now apply the @connect directive to a type!

GraphQL
1type Product
2  @connect(
3    source: "myApi"
4    http: {GET: "/products/{$this.id}"}
5    selection: "id name price"
6  )
7{
8  id: ID!
9  name: String
10  price: String
11}

This works just like an entity: true field on Query, but with no field on query! If you want to add extra fields to a type (via entities), and don't need the root field, this is the way to go.

$batch for avoiding N+1

If you have a REST endpoint which can accept a list of IDs and return a list of objects, you can use the $batch variable to avoid the N+1 problem. $batch is only available in Connectors that are on types (see above).

Previously, if you had a schema like this:

GraphQL
1type Query {
2  product(id: ID!): Product @connect(
3    source: "myApi"
4    http: {GET: "/product/{$args.id}"}
5    selection: "id name reviews { id }"
6  )
7  review(id: ID!): Review! @connect(
8    source: "myApi"
9    http: {GET: "/reviews/{$args.id}"}
10    selection: "id text rating"
11    entity: true
12  )
13}
14
15type Product {
16  id: ID!
17  name: String
18  price: String
19  reviews: [Review!]!
20}
21
22type Review {
23  id: ID!
24  text: String!
25  rating: Int!
26}

The /reviews endpoint would be called once for each review ID on the product. If you have an endpoint that resolves multiple reviews, you can instead do something like this:

GraphQL
1type Query {
2  product(id: ID!): Product @connect(
3    source: "myApi"
4    http: {GET: "/product/{$args.id}"}
5    selection: "id name reviews { id }"
6  )
7}
8
9type Product {
10  id: ID!
11  name: String
12  price: String
13  reviews: [Review!]!
14}
15
16type Review @connect(
17  source: "myApi"
18  http: {
19    POST: "/reviews"
20    body: "ids: $batch.id"
21  }
22  selection: "id text rating"
23) {
24  id: ID!
25  text: String!
26  rating: Int!
27}

$batch works just like $this, but it is always an array of the objects being resolved, rather than a single value.

In this example, we use a JSON body to pass the list of IDs to the endpoints, but you can also use queryParams

Limiting batch sizes

When using the $batch variable, you can limit how many IDs are sent in a single request using batch.maxSize:

GraphQL
1type Review @connect(
2  source: "myApi"
3  http: {
4    POST: "/reviews"
5    body: "ids: $batch.id"
6  }
7  batch: {maxSize: 5}  # If there are more than 5 reviews, they will be split into multiple requests
8  selection: "id text rating"
9) {
10  id: ID!
11  text: String!
12  rating: Int!
13}

More ways to build URLs

More flexible templates

Some restrictions on the templates used in @connect URLs have been lifted, allowing expressions in a few more places. For example:

GraphQL
1type Query {
2  products(filterName: String, filterValue: String): [Product] @connect(
3    source: "myApi"
4    http: {GET: "/products?{$args.filterName}={$args.filterValue}"}
5    selection: "id name reviews { id }"
6  )
7}

Setting the query parameter name was not previously allowed, only the value.

Dynamic expressions will still always be percent-encoded and are still not allowed to modify the domain of the URL.

Adding multiple path parameters dynamically

The new http.path variable is available in both @source and @connect, and allows appending multiple path parameters to the URL. It uses the same mapping expressions as other parts of Connectors.

GraphQL
1extend schema
2  @source(name: "myApi", http: {
3    baseURL: "http://example.com",
4    path: "$config.pathComponents"
5  })
6
7type Query {
8  products(pathComponents: [String!]!): [Product] @connect(
9    source: "myApi"
10    http: {GET: "/products", path: "$args.pathComponents"}
11    selection: "id name reviews { id }"
12  )
13}

Path components will be appended starting with @source(http.baseURL), then @source(http.path), then the @connect template, and finally @connect(http.path). Expressions in http.path must evaluate to arrays of scalars. Each value in that array will be percent-encoded and appended with a new slash.

The example above might result in a URL like http://example.com/from/config/products/from/arguments.

Adding multiple query parameters dynamically

The new http.queryParams attribute works much like http.path, but must evaluate to an object where each key is a query parameter name and each value is a query parameter value or list of values. Query parameters are appended (not overridden) in the same order as path segments:

  1. Literal parameters in baseURL

  2. Dynamic parameters (for example, from $config) in @source(http.queryParams)

  3. Query parameters from the connect template (static or from { } expressions)

  4. Dynamic parameters in @connect(http.queryParams)

The last of those is especially important for batching:

GraphQL
1type Review @connect(
2  source: "myApi"
3  http: {
4    GET: "/reviews"
5    queryParams: "id: $batch.id"
6  }
7  selection: "id text rating"
8) {
9  id: ID!
10  text: String!
11  rating: Int!
12}

Because $batch.id is an array of IDs, the resulting URL will have multiple id query parameters, like http://example.com/reviews?id=1&id=2&id=3.

Feedback

Ask Community