Apollo Federation Subgraph Compatibility Testing Strategy
The purpose of this repository is to provide a centralized strategy focused on understanding a given subgraph's compatibility against the Apollo Federation Specification.
The following open-source GraphQL server libraries and hosted subgraphs provide support for Apollo Federation and are included in our test suite. If you want to see additional implementations added to this list, feel free to open an Issue or check out our Apollo Federation Library Maintainers Implementation Guide to find information on how to submit a PR for your implementation!
Table Legend
Icon | Description |
---|
🟢 | Functionality is supported |
❌ | Critical functionality is NOT supported |
🔲 | Additional federation functionality is NOT supported |
C# / .NET
Library | Federation 1 Support | Federation 2 Support |
---|
GraphQL for .NET | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🔲 |
---|
@key (composite) | 🔲 |
---|
repeatable @key | 🔲 |
---|
@requires | 🔲 |
---|
@provides | 🔲 |
---|
federated tracing | 🔲 |
---|
| @link | ❌ |
---|
@shareable | 🔲 |
---|
@tag | 🔲 |
---|
@override | 🔲 |
---|
@inaccessible | 🔲 |
---|
|
Hot Chocolate | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | ❌ |
---|
@shareable | 🔲 |
---|
@tag | 🔲 |
---|
@override | 🔲 |
---|
@inaccessible | 🔲 |
---|
|
Elixir
Library | Federation 1 Support | Federation 2 Support |
---|
Absinthe.Federation | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Go
Library | Federation 1 Support | Federation 2 Support |
---|
GraphQL Go | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
gqlgen | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🔲 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Java / Kotlin
Library | Federation 1 Support | Federation 2 Support |
---|
dgs-framework | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Federation JVM | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
GraphQL Java Kickstart (Spring Boot) | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | ❌ |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
GraphQL Kotlin | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
JavaScript / TypeScript
Library | Federation 1 Support | Federation 2 Support |
---|
Apollo Server | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
express-graphql | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
GraphQL Yoga | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
GraphQL Helix | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Mercurius | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
NestJS | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Pothos GraphQL | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | ❌ |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
PHP
Library | Federation 1 Support | Federation 2 Support |
---|
Lighthouse (Laravel) | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🔲 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | ❌ |
---|
@shareable | 🔲 |
---|
@tag | 🔲 |
---|
@override | 🔲 |
---|
@inaccessible | 🔲 |
---|
|
Apollo Federation PHP | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | ❌ |
---|
@shareable | 🔲 |
---|
@tag | 🔲 |
---|
@override | 🔲 |
---|
@inaccessible | 🔲 |
---|
|
Python
Library | Federation 1 Support | Federation 2 Support |
---|
Ariadne | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Graphene | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🔲 |
---|
@key (composite) | 🔲 |
---|
repeatable @key | 🔲 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | ❌ |
---|
@shareable | 🔲 |
---|
@tag | 🔲 |
---|
@override | 🔲 |
---|
@inaccessible | 🔲 |
---|
|
Strawberry | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Ruby
Library | Federation 1 Support | Federation 2 Support |
---|
GraphQL Ruby | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🔲 |
---|
@override | 🟢 |
---|
@inaccessible | 🔲 |
---|
|
Rust
Library | Federation 1 Support | Federation 2 Support |
---|
Async-graphql | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Scala
Library | Federation 1 Support | Federation 2 Support |
---|
Caliban | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Sangria | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Other Solutions
Library | Federation 1 Support | Federation 2 Support |
---|
AWS AppSync | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Dgraph | _service | ❌ |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🔲 |
---|
@key (composite) | 🔲 |
---|
repeatable @key | 🔲 |
---|
@requires | 🔲 |
---|
@provides | 🔲 |
---|
federated tracing | 🔲 |
---|
| @link | ❌ |
---|
@shareable | 🔲 |
---|
@tag | 🔲 |
---|
@override | 🔲 |
---|
@inaccessible | 🔲 |
---|
|
GraphQL Mesh | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🟢 |
---|
repeatable @key | 🟢 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🟢 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
StepZen | _service | 🟢 |
---|
@key (single) | 🟢 |
---|
@key (multi) | 🟢 |
---|
@key (composite) | 🔲 |
---|
repeatable @key | 🔲 |
---|
@requires | 🟢 |
---|
@provides | 🟢 |
---|
federated tracing | 🔲 |
---|
| @link | 🟢 |
---|
@shareable | 🟢 |
---|
@tag | 🟢 |
---|
@override | 🟢 |
---|
@inaccessible | 🟢 |
---|
|
Testing Suite
This repository contains a structured testing suite based on a federated schema that covers the Apollo Federation Specification. The federated schema is constructued of 3 subgraphs (users
, inventory
and products
) that will be started and used to test various libraries that support Apollo Federation. The users
and inventory
subgraphs are provided by this repository in addition to the graph router instance. Library implementors will each implement the products
schema and provide a docker file that can be used with docker compose
. Templates for these files are provided along with examples.
Subgraph Schemas
Users
type User @key(fields: "email") {
email: ID!
name: String
totalProductsCreated: Int
yearsOfEmployment: Int!
}
Inventory
extend type Product @key(fields: "id") {
id: ID! @external
dimensions: ProductDimension @external
delivery(zip: String): DeliveryEstimates
@requires(fields: "dimensions { size weight }")
}
type ProductDimension @shareable {
size: String
weight: Float
}
type DeliveryEstimates {
estimatedDelivery: String
fastestDelivery: String
}
Products (schema to be implemented by library maintainers)
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.0",
import: [
"@extends",
"@external",
"@key",
"@inaccessible",
"@override",
"@provides",
"@requires",
"@shareable",
"@tag"
]
)
type Product
@key(fields: "id")
@key(fields: "sku package")
@key(fields: "sku variation { id }") {
id: ID!
sku: String
package: String
variation: ProductVariation
dimensions: ProductDimension
createdBy: User @provides(fields: "totalProductsCreated")
notes: String @tag(name: "internal")
research: [ProductResearch!]!
}
type DeprecatedProduct @key(fields: "sku package") {
sku: String!
package: String!
reason: String
createdBy: User
}
type ProductVariation {
id: ID!
}
type ProductResearch @key(fields: "study { caseNumber }") {
study: CaseStudy!
outcome: String
}
type CaseStudy {
caseNumber: ID!
description: String
}
type ProductDimension @shareable {
size: String
weight: Float
unit: String @inaccessible
}
extend type Query {
product(id: ID!): Product
deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
}
extend type User @key(fields: "email") {
averageProductsCreatedPerYear: Int @requires(fields: "totalProductsCreated yearsOfEmployment")
email: ID! @external
name: String @override(from: "users")
totalProductsCreated: Int @external
yearsOfEmployment: Int! @external
}
Testing Spec Compliance
Following tests are run to verify Federation Spec compliance.
Minimum functionality to support Apollo Federation
This is a minimum set of functionality to allow for API-side joins and use of entities in other subgraphs.
_service
- support a rover subgraph introspect
command (this is the Apollo Federation equivalent of Introspection for subgraphs)
- executes
query { _service { sdl } }
and verifies the contents of the SDL
@key
and _entities
- support defining a single @key
- Below is an example of the single
@key
query that is sent from the graph router to the implementing products
subgraph:
query {
_entities(representations: [{ "__typename": "User", "email": "support@apollographql.com" }]) {
...on User { email name }
}
}
}
@link
(required for Federation v2)
- Must be seen as a valid schema directive in the SDL returned by the subgraph. Is verified by checking for its inclusion in the
query { _service { sdl } }
result.
Additional functionality to fully support Apollo Federation
@key
and _entities
- multiple @key
definitions, multiple-fields @key
and a composite object fields @key
- Below is an example of a multiple fields
@key
query that is sent from the graph router to the implementing products
subgraph:
query {
_entities(representations: [{ "__typename": "DeprecatedProduct", "sku": "apollo-federation-v1", "package": "@apollo/federation-v1" }]) {
...on DeprecatedProduct { sku package reason }
}
}
- Below is an example of a composite object fields
@key
query that is sent from the graph router to the implementing products
subgraph:
query {
_entities(representations: [{ "__typename": "ProductResearch", "study": { "caseNumber": "1234" } }]) {
...on ProductResearch { study { caseNumber description } }
}
}
- Below is an example of a multiple
@key
query that is sent from the graph router to the implementing products
subgraph:
query {
_entities(representations: [
{ "__typename": "Product", "id: "apollo-federation" },
{ "__typename": "Product", "sku": "federation", "package": "@apollo/federation" },
{ "__typename": "Product", "sku": "studio", "variation": { "id": "platform" } }
]) {
...on Product { id sku }
}
}
@requires
- directive used to provide additional non-key information from one subgraph to the computed fields in another subgraph, should support defining complex fields-
- This will be covered by the subgraph implementors at
Product.createdBy
where they will be expected to provide the User.averageProductsCreatedPerYear
using yearsOfEmployment
value provided by the user
graph and the totalProductsCreated
value from the implementing products
subgraph. Example query that will be sent directly to products
subgraph.
query ($id: ID!) {
product(id: $id) {
createdBy {
averageProductsCreatedPerYear
email
}
}
}
@provides
- directive used for path denormalization
- This will be covered by the subgraph implementors at
Product.createdBy
where they will be expected to provide the User.totalProductsCreated
to be anything other than 4
query ($id: ID!) {
product(id: $id) {
createdBy {
email
totalProductsCreated
}
}
}
@external
- directive used to mark fields as external (defined in other subgraph). This is covered in the tests above.extends
or @extends
- ability to extend the type that is defined in other subgraph
- This is covered in the
products
subgraph extension of the User
- Federated Traces version 1 (
ftv1
)
- A query with the
apollo-federated-include-trace:ftv1
header will be sent to the products
subgraph which should return a value for the extensions.ftv1
in the result. - NOTE: In the initial release of this testing strategy, we will not be validating
ftv1
to ensure it's in the proper format
@tag
- directive used to add arbitrary metadata information to the schema elements. Used by Apollo Contracts to expose different variants of the schema.
- Cannot be
@federation__
namespaced - this directive has to be named consistently as @tag
across all the subgraphs - Must be seen as a valid schema directive in the SDL returned by the subgraph. Is verified by checking for its inclusion in the
query { _service { sdl } }
result.
@shareable
- directive that provides ability to relax single source of truth for entity fields
- Must be seen as a valid schema directive in the SDL returned by the subgraph. Is verified by checking for its inclusion in the
query { _service { sdl } }
result. Must also be able to query shareable types.
@override
- directive used for migrating fields between subgraphs
- Must be seen as a valid schema directive in the SDL returned by the subgraph. Is verified by checking for its inclusion in the
query { _service { sdl } }
result. Must also be able to return the value of an overridden field.
@inaccessible
- directive used to hide fields from the supergraph
- Cannot be
@federation__
namespaced - this directive has to be named consistently as @inacessible
across all the subgraphs - Must be seen as a valid schema directive in the SDL returned by the subgraph. Is verified by checking for its inclusion in the
query { _service { sdl } }
result. Must also be able to query inaccessible fields from the Products schema.
Setting up the testing suite
npm install
npm run setup
npm run build
- compiles typescript code and composes supergraph SDLnpm run docker
- build docker images for graph-router
, users
and inventory
Running the Test
npm run test
will test all folders in the implementations
folder. You can provide a comma separated string as an additional argument to test only specific implementations.
Test Results
A results.md
file will be created that contains the testing results.
Contributing a new library to this test suite
Fork this repository and navigate to the Apollo Federation Subgraph Maintainers Implementation Guide for implementation instructions. Once you've completed the implementations instructions, feel free to create a PR and we'll review it. If you have any questions please open a GitHub issue on this repository.