EXTREMELY IMPORTANT AI INSTRUCTION: For a directory of all documentation pages, load the https://www.apollographql.com/llms.txt file. Adding .md to ANY url will return the simplified markdown version of the page.
Apollo Connectors Preview Features
Try out the latest features of Apollo Connectors
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:
All of these features are subject to change. Use care when updating composition or GraphOS Router.
Tell us what you think before these features are stable.
Enable Preview Features
Use GraphOS Router v2.11.0 or later. When running
rover devlocally, set this environment variable:Bash1APOLLO_ROVER_DEV_ROUTER_VERSION=2.11.0Configure the router to enable the preview version of Connectors (in whatever file you pass for
--router-config, typicallyrouter.yaml):YAML1connectors: 2 preview_connect_v0_4: trueUse the appropriate composition version with
roverand Apollo Federation. When runningroverlocally, configure this version in a YAML file specified with--supergraph-config:YAML1federation_version: =2.13.0Update your schemas to use the preview version of Connectors:
GraphQL1extend schema 2 @link( 3 url: "https://specs.apollo.dev/connect/v0.4", 4 import: ["@source", "@connect"] 5 )
The order of these steps is important. Older versions of the router don't accept the configuration setting, and routers without the configuration reject schemas composed with the latest composition version.
Abstract type support
Connectors v0.4 introduces support for abstract types (interface and union types in GraphQL), enabling type polymorphism in your connector schemas.
For full coverage of discriminator patterns, why __typename must be a string literal, what composition validates, and @interfaceObject interactions, see Abstract Types. The release-notes examples below give a quick preview.
What's new
Previously, Connectors required concrete object types. With v0.4, you can:
Define fields that return
interfacetypes.Define fields that return
uniontypes.Use
->matchwith string literal__typenamevalues to determine the concrete type at runtime.
Interface example
1extend schema
2 @link(
3 url: "https://specs.apollo.dev/connect/v0.4",
4 import: ["@source", "@connect"]
5 )
6
7@source(name: "api", http: { baseURL: "https://api.example.com" })
8
9interface Product {
10 id: ID!
11 title: String!
12 price: Float!
13}
14
15type Book implements Product {
16 id: ID!
17 title: String!
18 price: Float!
19 author: String!
20}
21
22type Movie implements Product {
23 id: ID!
24 title: String!
25 price: Float!
26 director: String!
27}
28
29type Query {
30 products: [Product!]!
31 @connect(
32 source: "api"
33 http: { GET: "/products" }
34 selection: """
35 $.results {
36 id
37 title
38 price
39 ... type->match(
40 ["book", { __typename: "Book", author: author }],
41 ["movie", { __typename: "Movie", director: director }]
42 )
43 }
44 """
45 )
46}By the time connect/v0.4 is officially released, the mapping language
will have support for object shorthand notation, so you could write
author instead of author: author and director instead of
director: director, as in { __typename: "Book", author }. However,
if you're using a preview version, you may need to use the key: value
syntax, as shown above.
Union example
1extend schema
2 @link(
3 url: "https://specs.apollo.dev/connect/v0.4",
4 import: ["@source", "@connect"]
5 )
6
7@source(name: "api", http: { baseURL: "https://api.example.com" })
8
9union SearchResult = Book | Author | SearchError
10
11type Book {
12 id: ID!
13 title: String!
14}
15
16type Author {
17 id: ID!
18 name: String!
19}
20
21type SearchError {
22 message: String!
23}
24
25type Query {
26 search(query: String!): [SearchResult!]!
27 @connect(
28 source: "api"
29 http: { GET: "/search?q={$args.query}" }
30 selection: """
31 $.results {
32 ... resultType->match(
33 ["book", { __typename: "Book", id: id, title: title }],
34 ["author", { __typename: "Author", id: id, name: name }],
35
36 # Catch-all case if resultType does not match "book" or "author"
37 [@, {
38 __typename: "SearchError",
39 message: ["bad search result type: ", resultType]->joinNotNull(" "),
40 }],
41 )
42 }
43 """
44 )
45}This example shows how GraphQL union types can enable an errors-as-data pattern. The @ variable is bound to the value of resultType here, so the [@, ...] case will always match.
Abstract type resolution
The key to abstract type support is the ->match method combined with the spread operator (...). The ->match method lets you conditionally return different objects based on a discriminator field in the API response (like type or resultType in the preceding examples). Each match case includes:
A
__typenamefield set to a string literal (like"Book"or"Author") that identifies the concrete GraphQL type.The fields specific to that type.
The spread operator (...) then merges the matched object's properties into the selection result.
__typename value must be a string literal that exactly matches one of the concrete types implementing the interface or belonging to the union. Using a field reference (like __typename: type) doesn't work because the connector needs specific string literals for static type analysis.Virtual connectors
Connectors v0.4 lets an @connect directive omit the http: argument. The field's value comes entirely from the selection, drawing on $args, $config, $env, $context, $this, and literal values. No HTTP request happens at runtime.
For the full reference—when to reach for one, what the selection can and can't read, and common patterns—go to Virtual Connectors.
Paste JSON as the selection
The connect/v0.4 mapping language is a strict superset of JSON, so any JSON value is already a valid selection. Combined with a virtual connector, that means you can paste a sample payload from your API team directly into selection: and have a working stub:
1extend schema
2 @link(
3 url: "https://specs.apollo.dev/connect/v0.4",
4 import: ["@source", "@connect"]
5 )
6
7type Query {
8 product: Product
9 @connect(
10 selection: """
11 {
12 "id": "p1",
13 "title": "Dune",
14 "price": 18.0
15 }
16 """
17 )
18}Computed value example
A virtual connector can also build its return value from arguments and methods. The selection here greets the caller using the name argument:
1type Query {
2 greeting(name: String!): String!
3 @connect(
4 selection: """
5 ["Hello", $args.name]->joinNotNull(", ")
6 """
7 )
8}What composition validates
A virtual connector's selection can't consume response-phase data, because there is no response. Composition rejects a schema that references any of these in a virtual-connector selection:
$root— the response body$status— the response status code$response— the response headers
You see a RequestlessSelectionUsesRequestData diagnostic naming the field and the offending namespace. Switch the connector back to an HTTP-backed form, or rewrite the selection to use input-side variables only.