diff --git a/.cspell/cspell.yml b/.cspell/cspell.yml index 40215a748..c0148240b 100644 --- a/.cspell/cspell.yml +++ b/.cspell/cspell.yml @@ -39,6 +39,7 @@ overrides: ignoreRegExpList: - "\\]\\([^)]+\\)" - "youTubeID=.+/>" + - "WistiaId=.+/>" # Ignore user and repo names in GitHub links to supported subgraph libraries. - filename: '**/compatible-subgraphs.md' ignoreRegExpList: diff --git a/docs/README.md b/docs/README.md index 7c5b28dcd..ff6aa0e37 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,8 +2,8 @@ This is the documentation **source** for this repository. -The **deployed** version of the documentation for this repository is available at: +Pages from this directory are deployed in the following documentation sections: -* https://www.apollographql.com/docs/federation/ - -See the [docs site README](https://github.com/apollographql/docs) for local installation and development. +* https://www.apollographql.com/docs/graphos/schema-design/federated-schemas/federation +* https://www.apollographql.com/docs/graphos/reference/federation/versions +* https://www.apollographql.com/docs/graphos/reference/migration/to-federation-version-2 diff --git a/docs/shared/diagrams/federation-architecture.mdx b/docs/shared/diagrams/federation-architecture.mdx deleted file mode 100644 index 3338f6ee4..000000000 --- a/docs/shared/diagrams/federation-architecture.mdx +++ /dev/null @@ -1,14 +0,0 @@ -```mermaid -graph BT; - webapp(Web app); - iosapp(iOS app); - subgraph " "; - router([Router]); - serviceA[Users
subgraph]; - serviceB[Products
subgraph]; - serviceC[Reviews
subgraph]; - end; - webapp & iosapp -.- router; - router --- serviceA & serviceB & serviceC; - class webapp,iosapp secondary; -``` diff --git a/docs/shared/diagrams/managed-federation.mdx b/docs/shared/diagrams/managed-federation.mdx deleted file mode 100644 index d753fb425..000000000 --- a/docs/shared/diagrams/managed-federation.mdx +++ /dev/null @@ -1,17 +0,0 @@ -```mermaid -graph LR; - subgraph "Your infrastructure" - serviceA[Products subgraph]; - serviceB[Reviews subgraph]; - router([Router]); - end - subgraph "Apollo GraphOS" - registry{{Schema Registry}}; - uplink{{Uplink}} - end - serviceA & serviceB -->|"Publishes
schema"| registry; - registry -->|"Updates
config"| uplink; - router -->|Polls for config changes| uplink; - class registry secondary; - class uplink secondary; -``` diff --git a/docs/source/building-supergraphs/compatible-subgraphs.md b/docs/source/building-supergraphs/compatible-subgraphs.md deleted file mode 100644 index 6ec93a16e..000000000 --- a/docs/source/building-supergraphs/compatible-subgraphs.md +++ /dev/null @@ -1,1511 +0,0 @@ ---- -title: Federation-Compatible Subgraph Implementations -subtitle: Reference for compatible GraphQL server libraries -description: Reference for open-source GraphQL server libraries and hosted solutions that are compatible with Apollo Federation. ---- - -The following open-source GraphQL server libraries and hosted solutions support acting as a subgraph in a federated supergraph. Their support is tracked in Apollo's [subgraph compatibility repository](https://github.com/apollographql/apollo-federation-subgraph-compatibility). Check out the repository for details on the compatibility tests listed in the table below. - -> To add a subgraph to this list, feel free to open an [issue](https://github.com/apollographql/apollo-federation-subgraph-compatibility/issues) or check out the [Apollo Federation Subgraph Maintainers Implementation Guide](https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/main/CONTRIBUTORS.md) to learn how to submit a PR for your implementation! - -## Table Legend - -| Icon | Description | -| --- | --- | -| Maintained by Apollo | Maintained by Apollo | -| 🟒 | Functionality is supported | -| ❌ | Critical functionality is NOT supported | -| πŸ”² | Additional federation functionality is NOT supported | - -## Ballerina - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Ballerina GraphQL Module
- A spec-compliant, production-ready, Standard Library module for building and interacting with GraphQL APIs using Ballerina.
-
-Github: ballerina-platform/module-ballerina-graphql
-
-Type: Code first
-Stars: 144 ⭐
-Last Release: 2024-05-03
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requiresπŸ”²
@providesπŸ”²
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareableπŸ”²
@tagπŸ”²
@overrideπŸ”²
@inaccessibleπŸ”²
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
- -## C# / .NET - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
GraphQL for .NET
- GraphQL for .NET
-
-Github: graphql-dotnet/graphql-dotnet
-
-Type: Code first | SDL first
-Stars: 5.8k ⭐
-Last Release: 2024-02-06
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @keyπŸ”²
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link❌
@shareableπŸ”²
@tagπŸ”²
@overrideπŸ”²
@inaccessibleπŸ”²
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
Hot Chocolate
- Open-source GraphQL server for the Microsoft .NET platform that takes the complexity away and lets you focus on delivering the next big thing.
-
-Github: ChilliCream/graphql-platform
-
-Type: Code first | SDL first
-Stars: 4.9k ⭐
-Last Release: 2024-04-22
-
-Federation Library: apollographql/federation-hotchocolate -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## Elixir - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Absinthe
- The GraphQL toolkit for Elixir
-
-Github: absinthe-graphql/absinthe
-
-Type: Code first
-Stars: 4.2k ⭐
-Last Release: 2021-09-28
-
-Federation Library: DivvyPayHQ/absinthe_federation -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## Go - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
gqlgen
- go generate based graphql server library
-
-Github: 99designs/gqlgen
-
-Type: SDL first
-Stars: 9.6k ⭐
-Last Release: 2024-03-11
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
GraphQL Go (fork)
- This is a fork of graphql-go/graphql that adds Federation support
-
-Github: dariuszkuc/graphql
-
-Type: Code first
-Stars: 2 ⭐
-Last Release: 2022-11-11
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
- -## Java / Kotlin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
dgs-framework
- GraphQL for Java with Spring Boot made easy.
-
-Github: netflix/dgs-framework
-
-Type: SDL first
-Stars: 3.0k ⭐
-Last Release: 2024-04-30
-
-Core Library: GraphQL Java
-Federation Library: apollographql/federation-jvm  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
GraphQL Java Kickstart (Spring Boot)
- GraphQL and GraphiQL Spring Framework Boot Starters - Forked from oembedler/graphql-spring-boot due to inactivity.
-
-Github: graphql-java-kickstart/graphql-spring-boot
-
-Type: SDL first
-Stars: 1.5k ⭐
-Last Release: 2023-12-07
-
-Core Library: GraphQL Java
-Federation Library: apollographql/federation-jvm  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link❌
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
GraphQL Kotlin
- Libraries for running GraphQL in Kotlin
-
-Github: ExpediaGroup/graphql-kotlin
-
-Type: Code first
-Stars: 1.7k ⭐
-Last Release: 2024-04-18
-
-Core Library: GraphQL Java
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
Spring GraphQL
- Spring Integration for GraphQL
-
-Github: spring-projects/spring-graphql
-
-Type: SDL first
-Stars: 1.5k ⭐
-Last Release: 2024-04-16
-
-Core Library: GraphQL Java
-Federation Library: apollographql/federation-jvm  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## JavaScript / TypeScript - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Apollo Server
- 🌍  Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.
-
-Github: apollographql/apollo-server  Maintained by Apollo
-
-Type: SDL first
-Stars: 13.7k ⭐
-Last Release: 2024-04-18
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
express-graphql
- Create a GraphQL HTTP server with Express.
-
-Github: graphql/express-graphql
-
-Type: SDL first
-Stars: 6.3k ⭐
-Last Release: 2020-11-19
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
GraphQL Yoga
- The fully-featured GraphQL server with focus on easy setup, performance and great developer experience.
-
-Github: dotansimha/graphql-yoga
-
-Type: SDL first
-Stars: 8.0k ⭐
-Last Release: 2024-03-29
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
GraphQL Helix
- A highly evolved and framework-agnostic GraphQL HTTP server.
-
-Github: contra/graphql-helix
-
-Type: SDL first
-Stars: 831 ⭐
-Last Release: 2022-07-09
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
Mercurius
- Implement GraphQL servers and gateways with Fastify
-
-Github: mercurius-js/mercurius
-
-Type: SDL first
-Stars: 2.3k ⭐
-Last Release: 2024-04-22
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
NestJS (code first)
- A progressive Node.js framework for building efficient, reliable and scalable server-side applications.
-
-Github: nestjs/graphql
-
-Type: Code first
-Stars: 1.4k ⭐
-Last Release: 2024-02-07
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@providesπŸ”²
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObject🟒
-
NestJS (SDL First)
- A progressive Node.js framework for building efficient, reliable and scalable server-side applications.
-
-Github: nestjs/graphql
-
-Type: SDL first
-Stars: 1.4k ⭐
-Last Release: 2024-02-07
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
Pothos GraphQL
- Plugin based GraphQL schema builder that makes building graphql schemas with TypeScript easy, fast and enjoyable.
-
-Github: hayes/pothos
-
-Type: Code first
-Stars: 2.2k ⭐
-Last Release: 2024-04-17
-
-Core Library: GraphQL.js
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## PHP - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Lighthouse (Laravel)
- A framework for serving GraphQL from Laravel
-
-Github: nuwave/lighthouse
-
-Type: SDL first
-Stars: 3.3k ⭐
-Last Release: 2024-05-01
-
-Core Library: webonyx/graphql-php
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
GraphQL PHP
- PHP implementation of the GraphQL specification based on the reference implementation in JavaScript
-
-Github: webonyx/graphql-php
-
-Type: Code first
-Stars: 4.6k ⭐
-Last Release: 2024-03-11
-
-Federation Library: Skillshare/apollo-federation-php -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link❌
@shareableπŸ”²
@tagπŸ”²
@overrideπŸ”²
@inaccessibleπŸ”²
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
- -## Python - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Ariadne
- Python library for implementing GraphQL servers using schema-first approach.
-
-Github: mirumee/ariadne
-
-Type: SDL first
-Stars: 2.1k ⭐
-Last Release: 2024-03-18
-
-Core Library: GraphQL-core 3
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObject🟒
-
Graphene
- GraphQL framework for Python
-
-Github: graphql-python/graphene
-
-Type: Code first
-Stars: 8.0k ⭐
-Last Release: 2023-07-26
-
-Core Library: GraphQL-core 3
-Federation Library: graphql-python/graphene-federation -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
Strawberry
- A GraphQL library for Python that leverages type annotations πŸ“
-
-Github: strawberry-graphql/strawberry
-
-Type: Code first
-Stars: 3.8k ⭐
-Last Release: 2024-05-01
-
-Core Library: GraphQL-core 3
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## Ruby - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
GraphQL Ruby
- Ruby implementation of GraphQL
-
-Github: rmosolgo/graphql-ruby
-
-Type: Code first
-Stars: 5.3k ⭐
-Last Release: 2021-02-12
-
-Federation Library: Gusto/apollo-federation-ruby -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObject🟒
-
- -## Rust - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
async-graphql
- A GraphQL server library implemented in Rust
-
-Github: async-graphql/async-graphql
-
-Type: Code first
-Stars: 3.2k ⭐
-Last Release: 2022-11-28
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObjectπŸ”²
-
- -## Scala - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Caliban
- Functional GraphQL library for Scala
-
-Github: ghostdogpr/caliban
-
-Type: Code first
-Stars: 939 ⭐
-Last Release: 2024-04-16
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
Sangria
- Scala GraphQL implementation
-
-Github: sangria-graphql/sangria
-
-Type: Code first
-Stars: 2.0k ⭐
-Last Release: 2024-02-01
-
-Federation Library: sangria-graphql/sangria-federated -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## Swift - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
Graphiti
- The Swift GraphQL Schema framework for macOS and Linux
-
-Github: GraphQLSwift/Graphiti
-
-Type: SDL first
-Stars: 523 ⭐
-Last Release: 2023-11-15
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
- -## Other Solutions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LibraryFederation 1 SupportFederation 2 Support
AWS AppSync
- Serverless GraphQL and Pub/Sub APIs
-
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
Dgraph
- Dgraph is the native GraphQL database with a graph backend. It is open-source, scalable, distributed, highly available and lightning fast.
-
-
-
- - - - - - - - - -
_service❌
@key (single)🟒
@key (multi)πŸ”²
@key (composite)πŸ”²
repeatable @keyπŸ”²
@requiresπŸ”²
@providesπŸ”²
federated tracingπŸ”²
-
- - - - - - - - -
@link❌
@shareableπŸ”²
@tagπŸ”²
@overrideπŸ”²
@inaccessibleπŸ”²
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
Grafbase
- The GraphQL platform
-
-Github: grafbase/grafbase
-
-Type: Code first | SDL first
-Stars: 934 ⭐
-Last Release: 2024-02-23
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracingπŸ”²
-
- - - - - - - - -
@link❌
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
GraphQL Mesh
- Executable GraphQL schema from multiple data sources, query anything, run anywhere.
-
-Github: Urigo/graphql-mesh
-
- -Stars: 3.2k ⭐
-Last Release: 2024-04-30
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
Neo4J Graph Database
- A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations.
-
-Github: neo4j/graphql
-
-Type: Code first | SDL first
-Stars: 485 ⭐
-Last Release: 2024-04-30
-
-Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo -
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)🟒
repeatable @key🟒
@requires🟒
@provides🟒
federated tracing🟒
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirective🟒
@interfaceObject🟒
-
StepZen, an IBM Company
- Build GraphQL APIs for all your data in a declarative way. Federate across any data source, including GraphQL.
-
-
-
- - - - - - - - - -
_service🟒
@key (single)🟒
@key (multi)🟒
@key (composite)πŸ”²
repeatable @keyπŸ”²
@requires🟒
@providesπŸ”²
federated tracingπŸ”²
-
- - - - - - - - -
@link🟒
@shareable🟒
@tag🟒
@override🟒
@inaccessible🟒
@composeDirectiveπŸ”²
@interfaceObjectπŸ”²
-
diff --git a/docs/source/config.json b/docs/source/config.json deleted file mode 100644 index ac23fc41e..000000000 --- a/docs/source/config.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "title": "Federation", - "version": "v2", - "algoliaFilters": [ - "docset:federation", - [ - "docset:apollo-server", - "docset:rover", - "docset:router", - "docset:graphos" - ] - ], - "sidebar": { - "Introduction": "/", - "Quickstart": "/quickstart", - "Changelog": "/federation-versions", - "Building Your Supergraph": { - "Subgraphs": "/building-supergraphs/subgraphs-overview", - "Compatible Subgraph Libraries": "/building-supergraphs/compatible-subgraphs", - "Router": "/building-supergraphs/router", - "Apollo Server Subgraphs": "https://apollographql.com/docs/apollo-server/using-federation/apollo-subgraph-setup", - "JetBrains IDE Support": "/building-supergraphs/jetbrains-ide-support" - }, - "Federated Schemas": { - "Overview": "/federated-schemas/", - "Composition": "/federated-schemas/composition", - "Entities": { - "Introduction to Entities": "/entities/", - "Define Advanced Keys": "/entities/define-advanced-keys", - "Contribute and Reference Entity Fields": "/entities/contribute-fields", - "Resolve Another Subgraph's Fields": "/entities/resolve-another-subgraphs-fields", - "Use Contexts to Share Data": "/entities/use-contexts", - "Entity Interfaces": "/entities/interfaces", - "Migrate Fields": "/entities/migrate-fields", - "Handling the N+1 Problem": "entities/handling-n-plus-one" - }, - "Sharing Types (Value Types)": "/federated-schemas/sharing-types", - "Federated Directives": "/federated-schemas/federated-directives", - "Migrating from Schema Stitching": "/migrating-from-stitching" - }, - "Managed Federation": { - "Overview": "/managed-federation/overview", - "Setup": "/managed-federation/setup", - "Uplink": "/managed-federation/uplink", - "Federated Schema Checks": "/managed-federation/federated-schema-checks", - "Deployment Best Practices": "/managed-federation/deployment", - "Opt-In Error Reporting": "/managed-federation/error-reporting", - "Studio Features": "https://www.apollographql.com/docs/graphos/graphs/federated-graphs" - }, - "Performance": { - "Caching": "/performance/caching", - "Monitoring": "/performance/monitoring", - "Query Plans": "/query-plans" - }, - "Debugging & Metrics": { - "Error Codes": "/errors", - "Composition Hints": "/hints", - "Federated Trace Data": "/metrics", - "OpenTelemetry": "/opentelemetry" - }, - "API Reference": { - "Subgraph Specification": "/subgraph-spec", - "@apollo/subgraph": "https://apollographql.com/docs/apollo-server/using-federation/api/apollo-subgraph", - "@apollo/gateway": "https://apollographql.com/docs/apollo-server/using-federation/api/apollo-gateway" - }, - "Moving from Federation 1": { - "Changes from Federation 1": "/federation-2/new-in-federation-2", - "Steps to Move": "/federation-2/moving-to-federation-2", - "Backward Compatibility": "/federation-2/backward-compatibility" - } - } -} diff --git a/docs/source/entities/handling-n-plus-one.mdx b/docs/source/entities/handling-n-plus-one.mdx deleted file mode 100644 index 8fcf038ef..000000000 --- a/docs/source/entities/handling-n-plus-one.mdx +++ /dev/null @@ -1,202 +0,0 @@ ---- -title: Handling the N+1 Problem -subtitle: Enhance subgraph performance with the dataloader pattern -description: Learn how to optimize subgraph performance in GraphQL by efficiently handling reference resolvers to avoid the N+1 problem. ---- - -GraphQL developers often encounter the "N+1 query problem" with operations that return a list. -Consider this `TopReviews` query: - -```graphql disableCopy showLineNumbers=false -query TopReviews { - topReviews(first: 10) { - id - rating - product { - name - imageUrl - } - } -} -``` - -In a monolithic GraphQL server, the execution engine takes these steps: - -1. Resolve the `Query.topReviews` field, which returns a list of `Review`s. -2. For each `Review`, resolve the `Review.product` field. - -If `Query.topReviews` returns ten reviews, then the executor resolves `Review.product` field ten times. -If the `Reviews.product` field makes a database or REST query for a single `Product`, then there are ten unique calls to the data source. -This is suboptimal for the following reasons: - -- Fetching all products in a single query is more efficientβ€”for example, `SELECT * FROM products WHERE id IN ()`. -- If any reviews refer to the same product, then resources are wasted fetching data that was already retrieved. - -## The N+1 problem in a federated graph - -Consider the same `TopReviews` operation with the `Product` type as an entity defined in Reviews and Products subgraphs. - - - -```graphql title="Reviews subgraph" disableCopy -type Query { - topReviews(first: Int): [Review] -} - -type Review { - id: ID - rating: Int - product: Product -} - -type Product @key(fields: "id") { - id: ID -} -``` - -```graphql title="Products subgraph" disableCopy -type Product @key(fields: "id") { - id: ID! - name: String - imageUrl: String -} -``` - - - - -Most subgraph implementations use _reference resolvers_ to return the entity object corresponding to a key. -Although this pattern is straightforward, it can diminish performance when a client operation requests fields from many entities. -Recall the `topReviews` query, now in the context of a federated graph: - -```graphql disableCopy showLineNumbers=false -query TopReviews { - topReviews(first: 10) { # Defined in Reviews subgraph - id - rating - product { # ⚠️ NOT defined in Reviews subgraph - name - imageUrl - } - } -} -``` - -The router executes two queries: - -1. Fetch all fields except `Product.name` and `Product.imageURL` from the Reviews subgraph. -2. Fetch each product's `name` and `imageURL` from the Products subgraph. - - -In the Products subgraph, the reference resolver for `Product` doesn't take a list of keys but rather a single key. -Therefore, the subgraph library calls the reference resolver once for each key: - -```js {4-6} title="resolvers.js" disableCopy -// Products subgraph -const resolvers = { - Product: { - __resolveReference(productRepresentation) { - return fetchProductByID(productRepresentation.id); - } - }, - // ...other resolvers... -} -``` - -A basic `fetchProductByID` function might make a database call each time it's called. -If you need to resolve `Product.name` for `N` different products, this results in `N` database calls. -These calls are made in addition to the call made by the Reviews subgraph to fetch the initial list of reviews and the `id` of each product. -This problem can cause performance problems or even enable denial-of-service attacks. - -### Query planning to handle N+1 queries - -By default, the router's query planner handles N+1 queries for entities like the `Product` type. -The query plan for the `TopReviews` operation works like this: - -1. First, the router fetches the list of `Review`s from the Reviews subgraph using the root field `Query.topReviews`. The router also asks for the `id` of each associated product. -2. Next, the router extracts the `Product` entity references and fetches them in a batch to the Products subgraph's `Query._entities` root field. -3. After the router gets back the `Product` entities, it merges them into the list of `Review`s, indicated by the `Flatten` step. - -```mermaid -graph TB - A("Fetch (reviews)") --> B("Fetch (products)") - B --> C("Flatten (topReviews,[],products)") -``` - - - -``` -QueryPlan { - Sequence { - Fetch(service: "reviews") { - { - topReviews(first: 10) { - id - rating - product { - __typename - id - } - } - } - }, - Flatten(path: "reviews.@") { - Fetch(service: "products") { - { - ... on Product { - __typename - id - } - } => - { - ... on Product { - name - imageUrl - } - } - }, - }, - }, -} -``` - - - -Most subgraph implementations (including [`@apollo/subgraph`](/apollo-server/using-federation/api/apollo-subgraph/)) don't write the [`Query._entities` resolver](/graphos/reference/federation/subgraph-specific-fields/#query_entities) directly. -Instead, they use the [reference resolver API](/graphos/schema-design/federated-schemas/entities/intro/#2-define-a-reference-resolver) for resolving an individual entity reference: - -```js -const resolvers = { - Product: { - __resolveReference(productRepresentation) { - return fetchProductByID(productRepresentation.id); - }, - }, -}; -``` - -The motivation for this API relates to a subtle, critical aspect of the [subgraph specification](/federation/subgraph-spec): -the order of resolved entities must match the order of the given entity references. -If the entities are returned in the wrong order, those fields are merged with the wrong entities, leading to incorrect results. -To avoid this issue, most subgraph libraries handle entity order for you. - -Because order matters, it reintroduces the N+1 query problem: in the example above, `fetchProductByID` gets called once for each entity reference. - -## The dataloader pattern solution - -The solution for the N+1 problemβ€”whether for federated or monolithic graphsβ€”is the [dataloader](https://github.com/graphql/dataloader) pattern. -For example, in an Apollo Server implementation, using dataloaders could look like this: - -```js -const resolvers = { - Product: { - __resolveReference(product, context) { - return context.dataloaders.products(product.id); - }, - }, -}; -``` - -With dataloaders, when the query planner calls the Products subgraph with a batch of `Product` entities, the router makes a single batched request to the Products data source. - -Nearly every GraphQL server library provides a dataloader implementation, and Apollo recommends using it in every resolver, even those that aren't for entities or don't return a list. diff --git a/docs/source/federation-2/new-in-federation-2.mdx b/docs/source/federation-2/new-in-federation-2.mdx deleted file mode 100644 index 9974e1cee..000000000 --- a/docs/source/federation-2/new-in-federation-2.mdx +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: Changes from Apollo Federation 1 -subtitle: Learn what's new in Apollo Federation 2 -description: Explore the improvements and changes from Apollo Federation 1 to Federation 2, enhancing flexibility and schema composition in GraphQL. ---- - -Apollo Federation 2 provides developer experience improvements to the original specification for Apollo Federation (called _Federation 1_ in these docs). If your organization has an existing Federation 1 graph, this article summarizes the benefits of [moving to Federation 2](/graphos/reference/migration/to-federation-version-2/). - - - -If you're just getting started with Federation, check out the [Quickstart](/graphos/get-started/quickstart). - - - -## What isn't changing? - -Before covering what's new, here's what isn't changing in Federation 2: - -* Most importantly, Federation 2 is backward compatible with most Federation 1 supergraphs. You can probably move your existing supergraph to use Federation 2 composition without making any changes. - * Graphs that do require changes are graphs that should cause composition errors, but Federation 1 fails to detect them. [Learn more.](/graphos/reference/migration/backward-compatibility#do-i-need-to-modify-my-subgraph-schemas-to-use-federation-2) - * To take full advantage of Federation 2 features, you do need to make some changes to your subgraph schemas, but you can make these changes incrementally at your convenience. See [Moving to Apollo Federation 2](/graphos/reference/migration/to-federation-version-2/). - -* Subgraph servers have no additional requirements. Any [subgraph-compatible library](/graphos/reference/federation/compatible-subgraphs) is automatically compatible with Federation 2. - * Many subgraph-compatible libraries do not yet automatically define certain directives that are new in Federation 2, such as `@shareable`. You can [define these directives manually](/graphos/reference/migration/to-federation-version-2/#add-directive-definitions-if-needed) to use them in your subgraph schemas. - -## More flexible composition - -Federation 2 improves the flexibility and independence of your subgraph schemas. New composition logic is more flexible compared to Federation 1, meaning teams can more confidently build out their subgraphs or migrate functionality between subgraphs. - -Let's look at some examples! - -## Value types - -In Federation 1, multiple subgraphs can define the same type, but those definitions must all be identical. These identical shared types are called _value types_: - -

Fed. 1

- - - -```graphql title="Subgraph A" -type Book { - title: String! - author: String! -} -``` - -```graphql title="Subgraph B" -type Book { - title: String! - author: String! -} -``` - - - -In Federation 2, this "identical definition" constraint is removed. Value types and their fields can be shared across subgraphs, even if certain details differ between definitions. - -For details, see the sections below, along with [Value types](/graphos/schema-design/federated-schemas/sharing-types/). - -### Objects - -In Federation 2, an object type can be shared between subgraphs like so: - -

Fed. 2

- - - -```graphql title="Subgraph A" -type Book @shareable { - title: String! - author: String! -} -``` - -```graphql {3-4} title="Subgraph B" -type Book @shareable { - title: String! - author: String # Nullable - isbn: String! # Not in A -} -``` - - - -The two `Book` type definitions above differ in terms of the fields they include and the nullability of those fields. Notice also the new [`@shareable`](/graphos/schema-design/federated-schemas/sharing-types/#using-shareable) directive, which is required to indicate that a field can be resolved by multiple subgraphs. - - - -Marking a type as `@shareable` (as with `Book` above) is equivalent to marking all of its fields as `@shareable`. - - - -This flexibility is especially helpful when an organization has multiple standalone GraphQL APIs that they want to unify with federation. Such APIs often share some types, and this added flexibility reduces the work required to compose their schemas successfully. - -#### Valid shared field differences between subgraphs - -* The return type of a shared field can vary in nullability (`String` / `String!`). -* Types can omit fields that are included in other subgraphs, as long as every field in your supergraph is always resolvable. (For details, see [Rules of composition](/graphos/reference/federation/composition-rules).) - -For details on how these field differences are handled, see [Differing shared fields](/graphos/schema-design/federated-schemas/sharing-types/#differing-shared-fields). - -### Enums, unions, and interfaces - -In Federation 2, `enum`, `union`, and `interface` definitions can differ between subgraphs. For details, see [Merging types from multiple subgraphs](/graphos/reference/federation/composition-rules#merging-types-from-multiple-subgraphs). - -## Entities - -Federation 2 introduces subtle but powerful changes to [entities](/graphos/get-started/guides/federate-schemas#entity-overview). - -### Originating subgraphs - -In Federation 1, an entity originates in one subgraph and is then extended in other subgraphs: - -

Fed. 1

- - - -```graphql title="Products (originating)" -type Product @key(fields: "id") { - id: ID! - name: String! - price: Int -} -``` - -```graphql title="Inventory (extending)" -extend type Product @key(fields: "id") { - id: ID! @external - inStock: Boolean! -} -``` - - - -In Federation 2, entities don't have an "originating subgraph." Instead, each subgraph can define an entity and contribute fields to it: - -

Fed. 2

- - - -```graphql title="Products" -type Product @key(fields: "id") { - id: ID! - name: String! - price: Int -} -``` - -```graphql title="Inventory" -type Product @key(fields: "id") { - id: ID! - inStock: Boolean! -} -``` - - - -For details, see [Contributing entity fields](/graphos/schema-design/federated-schemas/entities/contribute-fields). - -### Shared entity fields - -In Federation 1, each entity field is resolved by exactly one subgraph (unless it's a `@key` field or part of a `@provides` directive). In Federation 2, multiple subgraphs can resolve the same entity field if they all mark it with the `@shareable` directive: - -

Fed. 2

- - - -```graphql {3} title="Products" -type Product @key(fields: "id") { - id: ID! - name: String! @shareable - price: Int -} -``` - -```graphql {3} title="Inventory" -type Product @key(fields: "id") { - id: ID! - name: String! @shareable - inStock: Boolean! -} -``` - - - -For more information, see [Resolving another subgraph's field](/graphos/schema-design/federated-schemas/entities/resolve-another-subgraphs-fields). - -### Changes to `@key` - -Federation 2 adds a new optional argument to the `@key` directive: `resolvable`. You can set this argument to `false` to indicate that a particular subgraph doesn't define a [reference resolver](/graphos/schema-design/federated-schemas/entities/intro/#2-define-a-reference-resolver) for that entity. - -For example: - -

Fed. 2

- - - -```graphql title="Products" -type Product @key(fields: "id") { - id: ID! - name: String! - price: Int -} -``` - -```graphql {1} title="Reviews" -type Product @key(fields: "id", resolvable: false) { - id: ID! -} - -type Review { - product: Product! - score: Int! -} -``` - - - -In this case, the Reviews subgraph references the `Product` entity by using it as the return type for `Review.product`. However, the subgraph doesn't contribute any unique fields to `Product`, so it doesn't need to define a reference resolver for it. Therefore, the "stub" definition of `Product` in the Reviews subgraph can include `resolvable: false`. - -For more information, see [Referencing an entity without contributing fields](/graphos/schema-design/federated-schemas/entities/contribute-fields#contributing-computed-entity-fields). - -### Migrating fields - -Federation 2 introduces the [`@override` directive](/graphos/reference/federation/directives/#override), which helps you safely migrate entity and root-level fields between subgraphs with managed federation: - - - -```graphql title="Payments subgraph" -type Bill @key(fields: "id") { - id: ID! - amount: Int! -} - -type Payment { - # ... -} -``` - -```graphql {3} title="Billing subgraph" -type Bill @key(fields: "id") { - id: ID! - amount: Int! @override(from: "Payments") -} -``` - - - -For details, see [Entity migration](/graphos/schema-design/federated-schemas/entities/migrate-fields). - -## Interfaces implementing interfaces - -Federation 1 composition incorrectly fails if an interface type implements another interface. This issue is resolved in Federation 2: - -

Fed. 2

- -```graphql -interface Media { - title: String! -} - -interface Book implements Media { - title: String! - author: String! -} -``` diff --git a/docs/source/images/federation-dark.svg b/docs/source/images/federation-dark.svg new file mode 100644 index 000000000..406982293 --- /dev/null +++ b/docs/source/images/federation-dark.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-1-dark.svg b/docs/source/images/federation-diag-1-dark.svg new file mode 100644 index 000000000..3e54326bf --- /dev/null +++ b/docs/source/images/federation-diag-1-dark.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-1.svg b/docs/source/images/federation-diag-1.svg new file mode 100644 index 000000000..2cf7060e8 --- /dev/null +++ b/docs/source/images/federation-diag-1.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-2-dark.svg b/docs/source/images/federation-diag-2-dark.svg new file mode 100644 index 000000000..3ca73f2d2 --- /dev/null +++ b/docs/source/images/federation-diag-2-dark.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-2.svg b/docs/source/images/federation-diag-2.svg new file mode 100644 index 000000000..fafe53edd --- /dev/null +++ b/docs/source/images/federation-diag-2.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-3-dark.svg b/docs/source/images/federation-diag-3-dark.svg new file mode 100644 index 000000000..c76567285 --- /dev/null +++ b/docs/source/images/federation-diag-3-dark.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-3.svg b/docs/source/images/federation-diag-3.svg new file mode 100644 index 000000000..b4c6a9314 --- /dev/null +++ b/docs/source/images/federation-diag-3.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-4-dark.svg b/docs/source/images/federation-diag-4-dark.svg new file mode 100644 index 000000000..8f3d1e612 --- /dev/null +++ b/docs/source/images/federation-diag-4-dark.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation-diag-4.svg b/docs/source/images/federation-diag-4.svg new file mode 100644 index 000000000..954f9793f --- /dev/null +++ b/docs/source/images/federation-diag-4.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/federation.svg b/docs/source/images/federation.svg new file mode 100644 index 000000000..64d1c3d58 --- /dev/null +++ b/docs/source/images/federation.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/managed-federation/deployment.mdx b/docs/source/managed-federation/deployment.mdx deleted file mode 100644 index 3e088dcbb..000000000 --- a/docs/source/managed-federation/deployment.mdx +++ /dev/null @@ -1,479 +0,0 @@ ---- -title: Deployment Best Practices -subtitle: Best practices and workflows for deploying with managed federation -description: Best practices and workflows for deploying a federated GraphQL API with Apollo Federation and GraphOS. ---- - -When rolling out changes to a subgraph, we recommend the following workflow: - -1. Confirm the backward compatibility of each change by [running `rover subgraph check`](/rover/commands/subgraphs/#validating-subgraph-schema-changes) in your CI pipeline. -2. Merge backward compatible changes that successfully pass schema checks. -3. Deploy changes to the subgraph in your infrastructure. -4. Wait until all replicas finish deploying. -5. Run [`rover subgraph publish`](/rover/commands/subgraphs/#publishing-a-subgraph-schema-to-graphos) to update your managed federation configuration: - -```bash -rover subgraph publish my-supergraph@my-variant \ - --schema ./accounts/schema.graphql \ - --name accounts \ - --routing-url https://my-running-subgraph.com/api -``` - -## Pushing configuration updates safely - -Whenever possible, you should update your subgraph configuration in a way that is backward compatible to avoid downtime. As suggested above, the best way to do this is to run `rover subgraph check` before updating. You should also generally seek to minimize the number of [breaking changes](/graphos/platform/schema-management/checks#potentially-breaking-changes) you make to your schemas. - -Additionally, call `rover subgraph publish` for a subgraph only after all replicas of that subgraph are deployed. This ensures that resolvers are in place for all operations that are executable against your graph, and operations can't attempt to access fields that do not yet exist. - -In the rare case where a configuration change is not backward compatible with your router's query planner, you should update your registered subgraph schemas before you deploy your updated code. - -You should also perform configuration updates that affect query planning prior to (and separately from) other changes. This helps avoid a scenario where the query planner generates queries that fail validation in downstream services or violate your resolvers. - -Examples of this include: - -- Modifying `@key`, `@requires`, or `@provides` directives -- Removing a type implementation from an interface - -In general, always exercise caution when pushing configuration changes that affect your router's query planner, and consider how those changes will affect your other subgraphs. - -### Example scenario - -Let's say we define a `Channel` interface in one subgraph, and we define types that implement `Channel` in two other subgraphs: - -```graphql -# channel subgraph -interface Channel @key(fields: "id") { - id: ID! -} - -# web subgraph -type WebChannel implements Channel @key(fields: "id") { - id: ID! - webHook: String! -} - -# email subgraph -type EmailChannel implements Channel @key(fields: "id") { - id: ID! - emailAddress: String! -} -``` - -To safely remove the `EmailChannel` type from your supergraph schema: - -1. Perform a `rover subgraph publish` of the `email` subgraph that removes the `EmailChannel` type from its schema. -2. Deploy a new version of the subgraph that removes the `EmailChannel` type. - -The first step causes the query planner to stop sending fragments `...on EmailChannel`, which would fail validation if sent to a subgraph that isn't aware of the type. - -If you want to keep `EmailType` but remove it from the `Channel` interface, the process is similar. Instead of removing the `EmailChannel` type altogether, only remove the `implements Channel` addendum to the type definition. This is because the query planner expands queries to interfaces or unions into fragments on their implementing types. - -For example, a query such as... - -```graphql -query FindChannel($id: ID!) { - channel(id: $id) { - id - } -} -``` - -...generates two queries, one to each subgraph, like so: - -```graphql -# Generated by the query planner - -# To email subgraph -query { - _entities(...) { - ...on EmailChannel { - id - } - } -} - -# To web subgraph -query { - _entities(...) { - ...on WebChannel { - id - } - } -} -``` - -Currently, the router expands all interfaces into implementing types. - -## Removing a subgraph - -To "de-register" a subgraph with Apollo, call `rover subgraph delete`: - - - -This action cannot be reversed! - - - -``` -rover subgraph delete my-supergraph@my-variant --name accounts -``` - -The next time it starts up or polls, your router obtains an updated configuration that reflects the removed subgraph. - -## Advanced deployment workflows - -With managed federation, you can control which version of your schema your router fleet uses. In most cases, rolling over all of your router instances to a new schema version is safe, assuming you've used [schema checks](/graphos/platform/schema-management/checks/) to confirm that your changes are backward compatible. Your deployment model, however, may require an advanced workflow to deploy a specific version of a schema. - -Two types of advanced deployment workflows: - -* **Blue-green deployment workflow**. For deployments that require progressive rollout, such as blue-green deployments, you can configure your environments to refer to a single [graph variant](/graphos/get-started/concepts/graphs-and-variants#variants) by pinning each environment's supergraph schema to your routers at deployment time. Using a single variant between different production environments enables GraphOS Studio to get usage reports and analyze the combined production traffic of all environments, as well as providing a consistent changelog of your schema over time. - -* **Graph variant workflow**. Changes at the router level might involve a variety of different updates, such as [migrating entities](/graphos/schema-design/federated-schemas/entities/migrate-fields) from one subgraph to another. If your infrastructure requires a more advanced deployment process to handle the different router updates, you can use [graph variants](/graphos/get-started/concepts/graphs-and-variants#variants) to manage router fleets running with different configurations. - - A common use for graph variants is [contracts](/graphos/platform/schema-management/delivery/contracts/overview), for example, to create separate contract variants for the public and private APIs of a supergraph schema. - -### Example blue-green deployment - - - -A blue-green deployment strategy uses two environments: one environment (blue) serves the schema variant for live traffic, and the other environment (green) uses a variant for a new release that's under development. When the new release is ready, traffic is migrated from the blue to the green environment. This cycle repeats with each new release. - -As an example, follow these steps to deploy with a supergraph schema of a new release (green) environment; the example uses the [GraphOS Platform API](/graphos/reference/platform-api/) to perform custom GraphOS actions: - -1. Publish all the release's subgraphs at once using the Platform API [`publishSubgraphs` mutation](https://studio.apollographql.com/graph/apollo-platform/variant/main/schema/reference/objects/GraphMutation#publishSubgraphs). - - ```graphql - ## Publish multiple subgraphs together in a batch - ## and retrieve the associated launch, along with any downstream launches synchronously. - mutation PublishSubgraphsMutation( - $graphId: ID! - $graphVariant: String! - $revision: String! - $subgraphInputs: [PublishSubgraphsSubgraphInput!]! - ) { - graph(id: $graphId) { - publishSubgraphs( #highlight-line - graphVariant: $graphVariant - revision: $revision - subgraphInputs: $subgraphInputs - downstreamLaunchInitiation: "SYNC" - ) { - launch { - id - downstreamLaunches { - id - graphVariant - status - } - } - } - } - } - ``` - - This initiates a [launch](/graphos/platform/schema-management/delivery/launch/), as well as any downstream launches necessary for [contracts](/graphos/platform/schema-management/delivery/contracts/create/#automatic-updates). It returns the launch IDs, with downstream launch IDs configured to return synchronously (`downstreamLaunchInitiation: "SYNC"`) with the mutation. - - - - For contracts, you can also request that any downstream launches return the variant associated with each launch, for example, `downstreamLaunches { graphVariant }`. When querying for a specific launch, be sure to pass the variant associated with the launch in the following steps. - - - -2. Poll for the completed launch and any downstream launches. - - ```graphql - ## Poll for the status of any individual launch by ID - query PollLaunchStatusQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) { - graph(id: $graphId) { - variant(name: $graphVariant) { - launch(id: $launchId) { - status - } - } - } - } - - ``` - - - - When polling for a contract, the `$graphVariant` argument of this query must refer to the contract variant rather than the base variant. You can get it from the query in step 1, from `Launch.graphVariant / downstreamLaunches { graphVariant }`. - - - -3. After the launch and downstream launches have completed, retrieve the supergraph schema of the launch. - - ```graphql - ## Fetch the supergraph SDL by launch ID. - query FetchSupergraphSDLQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) { - graph(id: $graphId) { - variant(name: $graphVariant) { - launch(id: $launchId) { - build { - result { - ... on BuildSuccess { - coreSchema { - coreDocument - } - } - } - } - } - } - } - } - - ``` - - - - When retrieving for a contract, the `$graphVariant` argument of this query must refer to a contract variant. You can get it from the query in step 1, from `Launch.graphVariant / downstreamLaunches { graphVariant }`. - - - -4. Deploy your routers with the [`-s` or `--supergraph` option](/graphos/reference/router/configuration#-s----supergraph) to specify the supergraph schema. - - * Specifying the `-s` or `--supergraph` option disables polling for the schema from Uplink. - - * For an example using the option in a `docker run` command, see [Specifying the supergraph](/graphos/routing/self-hosted/containerization/docker#specifying-the-supergraph). - -5. If you need to roll back to a previous blue-green deployment, ensure the previous deployment is available and shift traffic back to the previous deployment. - - * A router image must use an embedded supergraph schema via the `--supergraph` flag. - - * A deployment should include both router and subgraphs to ensure resolvers and schemas are compatible. - - * If a previous deployment can't be redeployed, repeat steps 3 and 4 with the `launchID` you want to roll back to. Ensure the deployed subgraphs are compatible with the supergraph schema, then redeploy the router with a newly fetched supergraph schema for your target `launchID`. Before considering only rolling back the supergraph schema, see its [caveats](#roll-back-supergraph-schema-only). - -### Example canary deployment - -A canary deployment applies graph updates in an environment separate from a live production environment and validates its updates starting with a small subset of production traffic. As updates are validated in the canary deployment, more production traffic is routed to it gradually until it handles all traffic. - -To configure your canary deployment, you can fetch the supergraph schema for a launchID for the canary deployment, then have that canary deployment report metrics to a `prod` variant. Similar to the [blue-green deployment example](#example-blue-green-deployment), your canary deployment is pinned to the same graph variant as your other, live deployment, so metrics from both deployments are reported to the same graph variant. As your canary deployment is scaled up, it will eventually become the stable deployment serving all production traffic, so we want that deployment reporting to the live `prod` variant. - -To configure a canary deployment for the `prod` graph variant: - -1. Publish all the canary deployment's subgraphs at once using the Platform API [`publishSubgraphs` mutation](https://studio.apollographql.com/graph/apollo-platform/variant/main/schema/reference/objects/GraphMutation#publishSubgraphs). - - ```graphql - ## Publish multiple subgraphs together in a batch - ## and retrieve the associated launch, along with any downstream launches synchronously. - mutation PublishSubgraphsMutation( - $graphId: ID! - $graphVariant: String! - $revision: String! - $subgraphInputs: [PublishSubgraphsSubgraphInput!]! - ) { - graph(id: $graphId) { - publishSubgraphs( #highlight-line - graphVariant: "prod" ## name of production variant - revision: $revision - subgraphInputs: $subgraphInputs - downstreamLaunchInitiation: "SYNC" - ) { - launch { - id - downstreamLaunches { - id - graphVariant - status - } - } - } - } - } - ``` - - This initiates a [launch](/graphos/platform/schema-management/delivery/launch/), as well as any downstream launches necessary for [contracts](/graphos/platform/schema-management/delivery/contracts/create/#automatic-updates). It returns the launch IDs, with downstream launch IDs configured to return synchronously (`downstreamLaunchInitiation: "SYNC"`) with the mutation. - - - - For contracts, you can also request that any downstream launches return the variant associated with each launch, for example, `downstreamLaunches { graphVariant }`. When querying for a specific launch, be sure to pass the variant associated with the launch in the following steps. - - - -2. Poll for the completed launch and any downstream launches. - - ```graphql - ## Poll for the status of any individual launch by ID - query PollLaunchStatusQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) { - graph(id: $graphId) { - variant(name: $graphVariant) { - launch(id: $launchId) { - status - } - } - } - } - - ``` - - - - When polling for a contract, the `$graphVariant` argument of this query must refer to the contract variant rather than the base variant. You can get it from the query in step 1, from `Launch.graphVariant / downstreamLaunches { graphVariant }`. - - - -3. After the launch and downstream launches have completed, retrieve the supergraph schema of the launch. - - ```graphql - ## Fetch the supergraph SDL by launch ID. - query FetchSupergraphSDLQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) { - graph(id: $graphId) { - variant(name: $graphVariant) { - launch(id: $launchId) { - build { - result { - ... on BuildSuccess { - coreSchema { - coreDocument - } - } - } - } - } - } - } - } - - ``` - - - - When retrieving for a contract, the `$graphVariant` argument of this query must refer to a contract variant. You can get it from the query in step 1, from `Launch.graphVariant / downstreamLaunches { graphVariant }`. - - - -4. Deploy your routers with the [`-s` or `--supergraph` option](/graphos/reference/router/configuration#-s----supergraph) to specify the supergraph schema. - - * Specifying the `-s` or `--supergraph` option disables polling for the schema from Uplink. - - * For an example using the option in a `docker run` command, see [Specifying the supergraph](/graphos/routing/self-hosted/containerization/docker#specifying-the-supergraph). - -5. If you need to roll back, ensure the previous deployment is available and shift traffic back to the live deployment. - - * A router image must use an embedded supergraph schema via the `--supergraph` flag. - - * A deployment should include both router and subgraphs to ensure resolvers and schemas are compatible. - - * If a previous deployment can't be redeployed, repeat steps 3 and 4 with the `launchID` you want to roll back to. Ensure the deployed subgraphs are compatible with the supergraph schema, then redeploy the router with a newly fetched supergraph schema for your target `launchID`. Before considering only rolling back the supergraph schema, see its [caveats](#roll-back-supergraph-schema-only). - -With your canary deployment [reporting metrics to GraphOS](/graphos/platform/insights/collection), you can use [GraphOS Studio](https://studio.apollographql.com?referrer=docs-content) to verify a canary's performance before rolling out changes to the rest of the graph. - -## Modifying query-planning logic - -Treat migrations of your query-planning logic similarly to how you treat database migrations. Carefully consider the effects on downstream services as the query planner changes, and plan for "double reading" as appropriate. - -Consider the following example of a `Products` subgraph and a `Reviews` subgraph: - -```graphql -# Products subgraph - -type Product @key(fields: "upc") { - upc: ID! - nameLowerCase: String! -} - -# Reviews subgraph - -type Product @key(fields: "upc") { - upc: ID! - reviews: [Review]! @requires(fields: "nameLowercase") - nameLowercase: String! @external -} -``` - -Let's say we want to deprecate the `nameLowercase` field and replace it with the `name` field, like so: - -```graphql -# Products subgraph - -type Product @key(fields: "upc") { - upc: ID! - nameLowerCase: String! @deprecated - name: String! -} - -# Reviews subgraph - -type Product @key(fields: "upc") { - upc: ID! - nameLowercase: String! @external - name: String! @external - reviews: [Review]! @requires(fields: "name") -} -``` - -To perform this migration in-place: - -1. Modify the `Products` subgraph to add the new field. (As usual, first deploy all replicas, then use `rover subgraph publish` to push the new subgraph schema.) -2. Deploy a new version of the `Reviews` subgraph with a resolver that accepts either `nameLowercase` or `name` in the source object. -3. Modify the Reviews subgraph's schema in the registry so that it `@requires(fields: "name")`. -4. Deploy a new version of the `Reviews` subgraph with a resolver that only accepts the `name` in its source object. - -Alternatively, you can perform this operation with an atomic migration at the subgraph level, by modifying the subgraph's URL: - -1. Modify the `Products` subgraph to add the `name` field (as usual, first deploy all replicas, then use `rover subgraph publish` to push the new subgraph schema). -2. Deploy a new set of `Reviews` replicas to a new URL that reads from `name`. -3. Register the `Reviews` subgraph with the new URL and the schema changes above. - -With this atomic strategy, the query planner resolves all outstanding requests to the old subgraph URL that relied on `nameLowercase` with the old query-planning configuration, which `@requires` the `nameLowercase` field. All new requests are made to the new subgraph URL using the new query-planning configuration, which `@requires` the `name` field. - -## Reliability and security - -Your router fetches its configuration by polling Apollo Uplink, an Apollo-hosted endpoint specifically for serving supergraph configs. In the event that your updated config is inaccessible due to an outage in Uplink, your router continues to serve its most recently fetched configuration. - -If you restart a router instance or spin up a new instance during an Uplink outage, that instance can't fetch its configuration until Apollo resolves the outage. - -## The `subgraph publish` lifecycle - -Whenever you call `rover subgraph publish` for a particular subgraph, it both updates that subgraph's registered schema and updates the router's managed configuration. - -Because your graph is dynamically changing and multiple subgraphs might be updated simultaneously, it's possible for changes to cause composition errors, even if `rover subgraph check` was successful. For this reason, updating a subgraph re-triggers composition in the cloud, ensuring that all subgraphs still compose to form a complete supergraph before updating the configuration. The workflow behind the scenes can be summed up as follows: - -1. The subgraph schema is uploaded to Apollo and indexed. -2. The subgraph is updated in the registry to use its new schema. -3. All subgraphs are composed in the cloud to produce a new supergraph schema. -4. If composition fails, the command exits and emits errors. -5. If composition succeeds, Apollo Uplink begins serving the updated supergraph schema. - -On the other side of the equation sits the router. The router can regularly poll Apollo Uplink for changes to its configuration. The lifecycle of dynamic configuration updates is as follows: - -1. The router polls for updates to its configuration. -2. On update, the router downloads the updated configuration, including the new supergraph schema. -3. The router uses the new supergraph schema to update its query planning logic. -4. The router continues to resolve in-flight requests with the previous configuration, while using the updated configuration for all new requests. - -Alternatively, instead of getting its configuration from Apollo Uplink, the router can specify a path to a supergraph schema upon its deployment. This static configuration is useful when you want the router to use a schema different than the latest validated schema from Uplink, or when you don't have connectivity to Apollo Uplink. For an example of this workflow, see an [example of configuring the router for blue-green deployment](#example-blue-green-deployment). - -## Rolling back a deployment - -When rolling back a deployment, you must ensure the supergraph schema and router version are compatible with the deployed subgraphs and subgraph schemas in the target environment, so all possible GraphQL operations can be successfully executed. - -### Roll forward to revert - -Rollbacks are typically implemented by rolling forward to a new version that reverts the changes in the subgraph code repository, then performing the full release process (publishing the subgraph schema and rolling out the new code together) as outlined in the [change management tech note](/technotes/TN0028-change-management/#rollbacks-1). This ensures the supergraph schema exposed by the router matches the underlying subgraphs. It's the safest approach when using the standard [schema delivery pipeline](/graphos/platform/schema-management) where Apollo Uplink provides the supergraph schema to the router for continuous deployment of new [launches](/graphos/platform/schema-management/delivery/launch). - -### Roll back entire deployment - -For blue-green deployment scenarios, where the router and subgraphs in a deployment have versioned Docker container images, you may be able to roll back the entire deployment (assuming no underlying database schema changes). Doing so ensures that the supergraph schema embedded in the router image is compatible with underlying subgraphs in the target environment. This kind of rollback is typically what happens when a blue-green deployment is aborted if [post-promotion analysis](https://argo-rollouts.readthedocs.io/en/stable/features/bluegreen/#postpromotionanalysis) fails. - -### Roll back supergraph schema only - -In rare circumstances where a backwards compatible subgraph schema-only change is made (for example, setting progressive `@override` percentage), it may be possible to only rollback the supergraph schema by pinning the router fleet to the supergraph schema for a specific `launchID` using the `--supergraph` flag. - -This approach is only suitable for short term fixes for a limited set of schema-only changes. It requires the router to pin to a specific supergraph `launchID`, as republishing the underlying subgraphs will result in a new supergraph schema being generated. - -Given the issues with this approach, in general we recommend implementing rollbacks by [rolling forward to a new version](#roll-forward-to-revert). - -### Rollback guidelines - -A summary of rollback guidelines: - -- Any rollback must ensure the router's supergraph schema is compatible with the underlying subgraphs deployed in the target environment. - -- GraphOS's standard CI/CD [schema delivery pipeline](/graphos/platform/schema-management) is the best choice for most environments seeking continuous deployment and empowerment of subgraph teams to ship both independently and with the safety of GraphOS checks to prevent breaking changes. For details, see the [change management tech note](/technotes/TN0028-change-management). - -- In environments with existing blue-green or canary deployments that rely on an immutable infrastructure approach—where no in-place updates, patches, or configuration changes can be made on production workloads—the router image can use an embedded supergraph schema. The supergraph schema is set for the router with the `--supergraph` flag for a specific GraphOS `launchID` that's generated by publishing the subgraph schemas for the specific subgraph image versions used in a blue-green or canary deployment. In this way, a blue-green or canary deployment can be made immutable as a whole, so rolling back to a previous deployment ensures the router's supergraph schema is compatible with the underlying subgraphs deployed in the target environment. - -- In general, we don't recommend rolling back only the supergraph schema on the router in isolation. Subgraph compatibility must also be taken into account. Subsequent publishing of subgraphs generates a new supergraph schema that may lose rolled back changes, so in general it's better to fix the problem at the source of truth in the subgraph repository. diff --git a/docs/source/managed-federation/error-reporting.mdx b/docs/source/managed-federation/error-reporting.mdx deleted file mode 100644 index 5b340e177..000000000 --- a/docs/source/managed-federation/error-reporting.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Opt-In Error Reporting for Managed Federation -subtitle: Configure out-of-band reporting -description: Learn how to configure your managed gateway to send error reports to Apollo via out-of-band reporting, improving performance and reliability. ---- - -You can configure your managed gateway to send error reports to Apollo via _out-of-band reporting_. These reports help Apollo improve the performance and reliability of managed federation. - -## Enabling reporting - -To enable out-of-band error reporting, set the following environment variable in your gateway's environment: - -```bash -APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT=https://outofbandreporter.api.apollographql.com -``` - -The next time you start up your gateway, out-of-band error reporting is enabled. - - - -If you've enabled out-of-band reporting in the past, you might have specified a URL that is now deprecated. Double-check your configuration to make sure you've specified the URL listed above. - - - -## How it works - -Whenever your gateway fails to fetch its supergraph schema from Apollo due to an error, the out-of-band reporting mechanism sends an error report to Apollo as a GraphQL mutation. - -The report provides the following information as GraphQL variables: - -* The error code and message produced by the gateway -* The HTTP Request URL and body -* The HTTP Response status code and body -* The `started-at` and `end-at` times of the request - -It also provides the following HTTP headers: - -* `apollographql-client-name`: The name of the GraphQL client used by the Gateway -* `apollographql-client-version`: The version number of the GraphQL client used by the Gateway diff --git a/docs/source/managed-federation/federated-schema-checks.mdx b/docs/source/managed-federation/federated-schema-checks.mdx deleted file mode 100644 index d664c68e6..000000000 --- a/docs/source/managed-federation/federated-schema-checks.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Federated Schema Checks -subtitle: Use schema checks for independent and safe subgraph development -description: Use GraphOS schema checks and the Rover CLI to enable independent and safe subgraph development in federated GraphQL architectures. ---- - - - -For an introduction to schema checks, see [Schema checks](/graphos/platform/schema-management/checks). - - - -Whenever you make changes to a subgraph schema, running `rover subgraph check` helps ensure that all your subgraph schemas still compose to a valid supergraph schema. This helps teams work independently on their portion of your federated graph without negatively affecting your users or other teams. - -When you run `rover subgraph check` on a particular subgraph, GraphOS Studio takes your schema changes and attempts to compose a supergraph schema from all of your registered subgraph schemas. - -- If composition succeeds, the result is compared against your most recently registered supergraph schema to confirm that no known clients are affected by the proposed changes. -- If composition fails, validation ends and results are returned to the user. - - - -Running `rover subgraph check` never updates your current registered supergraph schema. - - - -## Handling check failures - -There are two types of failures that can occur during validation: failed usage checks and failed composition. - -- Failed usage checks are failures due to breaking changes, like removing a field that an active client is querying. -- Failed composition is a failure due to inability to compose the graph, like missing a required `@key` for an entity. - -In most cases, you should run `rover subgraph publish` only after a successful run of `rover subgraph check`. However, certain workflows require intentionally publishing a subgraph schema that fails composition (such as [migrating an entity or field between subgraphs](/graphos/schema-design/federated-schemas/entities/migrate-fields)). - -Even after `rover subgraph check` succeeds, however, it's possible that `rover subgraph publish` encounters composition errors because of simultaneous changes to another subgraph. When this occurs, your subgraph's registered schema is still updated as long as it is spec-compliant. However, the supergraph schema is not updated. This means that your router's configuration is also not updated. - -An example output of this behavior looks like this: - -``` -$ rover subgraph publish docs-example-graph@current --name books --schema ./schema.graphql - -Publishing SDL to docs-example-graph:current (subgraph: books) using credentials from the default profile. -The gateway for the 'docs-example-graph' graph was NOT updated with a new schema -WARN: The following composition errors occurred: -Field "Author.name" can only be defined once. -There can be only one type named "Author". -Field "Book.title" can only be defined once. -Field "Book.author" can only be defined once. -There can be only one type named "Book". -``` - -The reasoning behind this functionality is that the Apollo schema registry should always reflect what is running in your infrastructure. Even if that means that composition is failing in your infrastructure, the registry should reflect that. - -However, you still want your router to function as it was before the most recent deployment. Additionally, this functionality can be used to make dependent changes, like smoothly migrating a field from one subgraph to another or introducing a circular dependency. diff --git a/docs/source/managed-federation/overview.mdx b/docs/source/managed-federation/overview.mdx deleted file mode 100644 index 6e733a065..000000000 --- a/docs/source/managed-federation/overview.mdx +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Managed Federation Overview -subtitle: Manage supergraph CI/CD with Apollo GraphOS -description: Use Apollo GraphOS to manage your supergraph including schema validation, composition, and configuration. ---- - -import ManagedFederationDiagram from '../../shared/diagrams/managed-federation.mdx'; - -Apollo GraphOS provides managed federation support for graphs that use Apollo Federation. - -With managed federation, you maintain subgraphs and delegate GraphOS to manage CI/CD tasks including the validation, composition, and update of your supergraph: - -* Your subgraphs publish their schemas to GraphOS, which stores them in its schema registry. GraphOS then [validates](/graphos/platform/schema-management/checks) and [composes](/graphos/schema-design/federated-schemas/composition) them into a supergraph schema. - -* Your routers can poll GraphOS—specifically, its [Apollo Uplink](/graphos/routing/uplink) endpoint—to get the latest validated supergraph schema and other configurations. - - - -## Benefits of managed federation - -Managed federation helps your organization safely validate, coordinate, deploy, and monitor changes to your graph. It provides: - -### Router stability - -You can modify subgraph schemas (and even add or remove entire subgraphs) without needing to modify or redeploy your router. Your router is the point of entry to your entire graph, and it should maximize its uptime. - -### Composition stability - -Whenever your router obtains an updated configuration from Apollo, it knows that the updated set of subgraph schemas will compose, because the configuration includes the composed supergraph schema. - -The router also knows that your subgraphs are prepared to handle operations against the updated set of schemas. This is because your subgraphs should publish their updated schemas as part of their deployment, meaning they're definitely running by the time the router is aware of the configuration change. - -And whenever a subgraph accidentally pushes a schema change that doesn't compose, GraphOS continues to provide the most recent valid configuration to your router. - -### Schema flexibility - -By using a configuration manager that's external to your router, you help ensure the safety of certain schema changes. For example, if you want to migrate a type or field from one subgraph's schema to another, you can perform this migration safely only if you externalize your configuration. - -
- -Ready to try it out? Continue to [Setup](/graphos/get-started/quickstart). diff --git a/docs/source/managed-federation/setup.mdx b/docs/source/managed-federation/setup.mdx deleted file mode 100644 index 531b761cb..000000000 --- a/docs/source/managed-federation/setup.mdx +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: Setting Up Managed Federation -subtitle: Connect your supergraph to Apollo GraphOS -description: Learn how to connect your supergraph to the Apollo GraphOS platform for managed GraphQL federation. ---- - -This article describes how to connect your supergraph to Apollo GraphOS to enable managed federation features. - - - -As with all changes, you should first set up managed federation in a non-production environment, such as staging. To support this, you can create multiple [variants](/graphos/get-started/concepts/graphs-and-variants#variants) of your supergraph in GraphOS Studio. Each variant represents a distinct version of the same graph for different environments. - - - -## 1. Get started - -First, set up the tools required from [this tutorial](/graphos/get-started/quickstart), including: - -- Creating an Apollo account -- Creating a graph in Studio -- Installing and authenticating the Rover CLI - -## 2. Publish all subgraph schemas - -In a supergraph architecture, each of your subgraphs uses the Rover CLI to publish its schema to GraphOS: - -```mermaid -graph LR; - subgraph " " - router([Router]); - subgraphA[Products subgraph]; - subgraphB[Reviews subgraph]; - subgraphC[Inventory subgraph]; - end - registry{{GraphOS
Schema Registry}}; - router --- subgraphA & subgraphB & subgraphC; - subgraphA & subgraphB & subgraphC -.->|rover subgraph publish| registry; - class registry secondary; -``` - -Do the following for each of your subgraphs: - -1. Obtain the following values, which are required for the `rover subgraph publish` command: - - * The name that uniquely identifies the subgraph within your graph (e.g., `products`). - * The URL that your router will use to communicate with the subgraph (e.g., `http://products-graphql.svc.cluster.local:4001/`). - -2. Run the `rover subgraph publish` command, providing it your subgraph's schema in one of the ways shown: - - ```bash - # Provide a local .graphql file path - rover subgraph publish my-graph@my-variant --name products --routing-url http://products-graphql.svc.cluster.local:4001/ --schema ./schema.graphql - - # Provide an introspection result via stdin - rover subgraph introspect http://localhost:4000 | rover subgraph publish my-graph@my-variant --name products --routing-url http://products-graphql.svc.cluster.local:4001/ --schema - - ``` - -As you register your subgraph schemas, the schema registry attempts to compose their latest versions into a single supergraph schema. Whenever composition succeeds, your managed router can fetch the latest supergraph schema from GraphOS. - -You can also manually fetch your latest supergraph schema with the `rover supergraph fetch` command, or retrieve it from your graph's **Schema > SDL** tab in GraphOS Studio. - -## 3. Modify your router's startup command - - - -If you've already set up Apollo Federation without connecting your gateway to GraphOS, the constructor of your `ApolloGateway` instance probably includes a `supergraphSdl` option, like this: - -```js {2} -const gateway = new ApolloGateway({ - supergraphSdl -}); -``` - -This option is specific to non-managed federation, in which supergraph schema composition is performed via the Rover CLI. - -With managed federation, composition can instead be performed by GraphOS, where the gateway regularly polls for an updated schema. This enables you to add, remove, and modify your subgraphs without needing to restart your gateway. - -To use managed federation, ensure your `ApolloGateway` constructor doesn't include the `supergraphSdl` argument: - -```js -const gateway = new ApolloGateway(); -``` - -When running your gateway in an environment where outbound traffic to the internet is restricted, consult the [directions for configuring a proxy](/apollo-server/security/proxy-configuration) within Apollo Server. - - - -If you've already set up Apollo Federation without connecting your router to GraphOS, you're probably passing the [`--supergraph` (or `-s`) option](/graphos/reference/router/configuration#-s----supergraph) to the GraphOS Router's startup command: - -```sh -./router --config ./router.yaml --supergraph ./your-local-supergraph.graphql -``` - -The `--supergraph` option applies in scenarios where the router doesn't retrieve the supergraph schema by polling Apollo Uplink. These include: - -* **Enabling different deployment environments to refer to a single graph variant**, for example, for [blue-green deployment](/federation/managed-federation/deployment/#example-blue-green-deployment): Use a workflow with the [Platform API](/graphos/reference/platform-api/) to compose and retrieve the supergraph schema for each environment. This enables each environment's router to use the environment's supergraph schema, and then a single graph variant can capture and analyze the operations and traffic of either environment when deployed. - -* **Unmanaged federation**: The Rover CLI composes the supergraph schema and passes the schema's file path to the router via the `--supergraph` option. - -For other scenarios where the router retrieves the supergraph schema from Apollo Uplink, remove the `--supergraph` option (but leave `--config` if it's present): - -```sh -./router --config ./router.yaml -``` - -With federation managed by GraphOS, composition is performed when subgraph schemas are published, and the router regularly polls for an updated supergraph schema from Apollo Uplink. This enables you to add, remove, and modify your subgraphs without needing to restart your router. - - -## 4. Connect your router to GraphOS - -Like your subgraphs, your router uses a graph API key to identify itself to GraphOS. - - - -After obtaining your graph API key, you set the following environment variables in your router's environment: - -- `APOLLO_KEY` (set this to your graph API key) -- `APOLLO_GRAPH_REF` - - This variable tells the router which variant of which graph to use (for example, `docs-example-graph@production`). You can find your variant's graph ref at the very top of its README page in GraphOS Studio. - -## 5. Deploy the modified router - -You can now deploy your modified router, which can either fetch its supergraph schema from GraphOS on startup or specify its supergraph schema for deployment in a particular environment. It can then begin executing operations across your subgraphs. diff --git a/docs/source/managed-federation/uplink.mdx b/docs/source/managed-federation/uplink.mdx deleted file mode 100644 index 025c83453..000000000 --- a/docs/source/managed-federation/uplink.mdx +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Apollo Uplink -subtitle: Fetch your managed router's configuration -description: Learn how to configure Apollo Uplink for managed GraphQL federation, including polling behavior and Uplink URLs. ---- - -When using [managed federation](/federation/managed-federation/overview/), your supergraph's router by default regularly polls an endpoint called _Apollo Uplink_ for its latest supergraph schema and other configuration: - -```mermaid -graph LR; - subgraph "Your infrastructure" - serviceA[Products subgraph]; - serviceB[Reviews subgraph]; - router([Router]); - end - subgraph "Apollo GraphOS" - registry{{Schema Registry}}; - uplink{{Uplink}} - end - serviceA & serviceB -->|"Publishes
schema"| registry; - registry -->|"Updates
config"| uplink; - router -->|Polls for config changes| uplink; - class registry secondary; - class uplink secondary; -``` - -If you're using [Enterprise features](https://www.apollographql.com/pricing), Uplink also serves your router's license. - -To maximize uptime, Uplink is hosted simultaneously at two endpoints, one in GCP and one in AWS: - -- GCP: `https://uplink.api.apollographql.com/` -- AWS: `https://aws.uplink.api.apollographql.com/` - -## Default polling behavior - -### GraphOS Router - -If you use the GraphOS Router with managed federation, it polls Uplink every ten seconds by default. Each time, it cycles through Uplink endpoints until it receives a response. - -Whenever a poll request times out or otherwise fails (the default timeout is thirty seconds), the router continues polling as usual at the next interval. In the meantime, it continues using its most recent successfully obtained configuration. - -### `@apollo/gateway` - -If you use the `@apollo/gateway` library with managed federation, your gateway polls Uplink every ten seconds by default. Each time, it cycles through Uplink endpoints until it receives a response. - - - -Versions of `@apollo/gateway` prior to v0.45.0 don't support multiple Uplink endpoints and only use the GCP endpoint by default. - - - -Whenever a poll request fails, the gateway retries that request (again, using round robin). It continues retrying until a request succeeds, or until reaching the defined maximum number of retries. - -Even if a particular poll request fails all of its retries, the gateway continues polling as usual at the next interval (with its own set of retries if needed). In the meantime, the gateway continues using its most recent successfully obtained configuration. - -## Configuring polling behavior - -You can configure the following aspects of your router's Uplink polling behavior: - -- The interval at which your router polls (minimum ten seconds) -- The list of Uplink URLs your router uses -- The request timeout for each poll request (GraphOS Router only) - - For `@apollo/gateway`, this value is always thirty seconds. -- The number of retries performed for a failed poll request (`@apollo/gateway` only) - - The GraphOS Router does not perform retries for a failed poll request. It continues polling at the next interval. - -### GraphOS Router - -You configure Uplink polling for the GraphOS Router by providing certain command-line options when running the router executable. These options all start with `--apollo-uplink`. - -[See the GraphOS Router docs](/graphos/reference/router/configuration#--apollo-uplink-endpoints). - -### `@apollo/gateway` - -#### Retry limit - -You can configure how many times your gateway retries a single failed poll request like so: - -```js {6} -const { ApolloGateway } = require('@apollo/gateway'); - -// ... - -const gateway = new ApolloGateway({ - uplinkMaxRetries: 2 -}); -``` - -By default, the gateway retries a single poll request a number of times equal to three times the number of [Uplink URLs](#uplink-urls-advanced) (this is almost always `6` times). - -Even if a particular poll request fails all of its retries, the gateway continues polling as usual at the next interval (with its own set of retries if needed). In the meantime, the gateway continues using its most recently obtained configuration. - -#### Poll interval - -You can configure the interval at which your gateway polls Apollo Uplink like so: - -```js {6} -const { ApolloGateway } = require('@apollo/gateway'); - -// ... - -const gateway = new ApolloGateway({ - pollIntervalInMs: 15000 // 15 seconds -}); -``` - -The `pollIntervalInMs` option specifies the polling interval in milliseconds. This value must be at least `10000` (which is also the default value). - -#### Uplink URLs (advanced) - - - -Most gateways never need to configure their list of Apollo Uplink URLs. Consult this section only if advised to do so. - - - -You can provide a custom list of URLs for the gateway to use when polling Uplink. You can provide this list either in the `ApolloGateway` constructor or as an environment variable. - -##### `ApolloGateway` constructor - -Provide a custom list of Uplink URLs to the `ApolloGateway` constructor like so: - -```js {6-9} -const { ApolloGateway } = require('@apollo/gateway'); - -// ... - -const gateway = new ApolloGateway({ - uplinkEndpoints: [ - // Omits AWS endpoint - 'https://uplink.api.apollographql.com/' - ] -}); -``` - -This example omits the AWS endpoint, which means it's never polled. - - - -If you also provide a list of endpoints via [environment variable](#environment-variable), the environment variable takes precedence. - - - -##### Environment variable - -You can provide a comma-separated list of Uplink URLs as the value of the `APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT` environment variable in your gateway's environment: - -```bash -APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT=https://aws.uplink.api.apollographql.com/,https://uplink.api.apollographql.com/ -``` - -## Schema size limit - -Supergraph schemas provided by Uplink cannot exceed 6MB in size. The vast majority of supergraph schemas are well below this limit. - -If your supergraph schema does exceed 6MB, you can set up a [build status webhook](/graphos/platform/insights/notifications/build-status) for your graph. Whenever you're notified of a successful supergraph schema composition, your webhook can fetch the latest supergraph schema [via the Rover CLI](/rover/commands/supergraphs#supergraph-fetch). - -## Bypassing Uplink - - - -In advanced use cases, you may want your router to use a supergraph schema different than the latest validated schema provided by Uplink. For example, you have different deployment environments for the same [graph variant](/graphos/get-started/concepts/graphs-and-variants#variants), and you want everything that managed federation provides except for your routers to use supergraph schemas specific to their deployment environment. - -For this scenario, you can follow a workflow that, instead of retrieving supergraph schemas from Uplink, uses the [GraphOS Platform API](/graphos/reference/platform-api) to retrieve a supergraph schema for a specific [GraphOS launch](/graphos/platform/schema-management/delivery/launch). The workflow, in summary: - -1. When deploying your graphs, publish your subgraphs in a batch using the GraphOS Platform API. - * The Platform API triggers a launch (and possible downstream launches for contracts) and returns the launch ID (and downstream launch IDs, if necessary). -1. Poll for the launch status, until the launch (and all downstream launches) has completed successfully. -1. Retrieve the supergraph schema of the successful launch by calling the Platform API with the launch ID. -1. Set or "pin" the supergraph schema to your routers by deploying them with the [`--supergraph` or `-s` option](/graphos/reference/router/configuration#-s----supergraph). - -For an example with operations calling the Platform API, see a [blue-green deployment example](/graphos/schema-design/guides/production-readiness/best-practices#example-blue-green-deployment). diff --git a/docs/source/metrics.md b/docs/source/metrics.md deleted file mode 100644 index 75aa0634d..000000000 --- a/docs/source/metrics.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: Federated Trace Data -subtitle: Reporting fine-grained performance metrics -description: Explore how federated traces enable fine-grained performance metrics reporting. Learn about the reporting flow and how tracing data is exposed and aggregated. ---- - -One of the many benefits of using GraphQL as an API layer is that it enables fine-grained, field-level [tracing](/graphos/metrics/#resolver-level-traces) of every executed operation. The [GraphOS platform](/graphos/) can consume and aggregate these traces to provide detailed insights into your supergraph's usage and performance. - -Your supergraph's router can generate _federated traces_ and [report them to GraphOS](/graphos/metrics/sending-operation-metrics). A federated trace is assembled from timing and error information provided by each subgraph that helps resolve a particular operation. - -## Reporting flow - -The overall flow of a federated trace is as follows: - -1. The router receives an operation from a client. -2. The router generates a [query plan](./query-plans/) for the operation and delegates sub-queries to individual subgraphs. -3. Each queried subgraph returns response data to the router. - - The [`extensions`](/resources/graphql-glossary/#extensions) field of each response includes trace data for the corresponding sub-query. - - The subgraph must support the federated trace format to include trace data in its response. See [this section](#in-your-subgraphs). -4. The router collects the set of sub-query traces from subgraphs and arranges them in the shape of the query plan. -5. The router [reports the federated trace to GraphOS](/graphos/metrics/sending-operation-metrics/) for processing. - -In summary, subgraphs report timing and error information to the router, and the router is responsible for aggregating those metrics and reporting them to GraphOS. - -## Enabling federated tracing - -### In your subgraphs - -For a subgraph to include trace data in its responses to your router, it must use a subgraph-compatible library that supports the trace format. - -To check whether your subgraph library supports federated tracing, see the `FEDERATED TRACING` entry for the library on [this page](./building-supergraphs/supported-subgraphs/). - -If your library does support federated tracing, see its documentation to learn how to enable the feature. - - - -If your subgraph uses Apollo Server with `@apollo/subgraph`, federated tracing is enabled by default. You can customize this behavior with Apollo Server's [inline trace plugin](/apollo-server/api/plugin/inline-trace). - - - -### In the Apollo Router - -See [Sending Apollo Router usage data to GraphOS](/router/configuration/telemetry/apollo-telemetry). - -### In `@apollo/gateway` - -You can use the `@apollo/server` package's [built-in usage reporting plugin](/apollo-server/api/plugin/usage-reporting) to enable federated tracing for your gateway. Provide an API key to your gateway via the `APOLLO_KEY` environment variable for the gateway to report metrics to the default ingress. To ensure that subgraphs do not report metrics as well, either do not provide them with an `APOLLO_KEY` or install the [`ApolloServerPluginUsageReportingDisabled` plugin](https://www.apollographql.com/docs/apollo-server/api/plugin/usage-reporting/) in your `ApolloServer`. - -These options will cause the Apollo gateway to collect tracing information from the underlying subgraphs and pass them on, along with the query plan, to the Apollo metrics ingress. - - - -By default, metrics are reported to the `current` GraphOS variant. To change the variant for reporting, set the `APOLLO_GRAPH_VARIANT` environment variable. - - - -## How tracing data is exposed from a subgraph - - - -This section explains how your router communicates with subgraphs around encoded tracing information. It is not necessary to understand in order to enable federated tracing. - - - -Your router inspects the `extensions` field of all subgraph responses for the presence of an `ftv1` field. This field contains a representation of the tracing information for the sub-query that was executed against the subgraph, sent as the Base64 encoding of the [protobuf representation](https://github.com/apollographql/apollo-server/blob/main/packages/usage-reporting-protobuf/src/reports.proto) of the trace. - -To obtain this information from a subgraph, the router includes the header pair `'apollo-federation-include-trace': 'ftv1'` in its request (if it's [configured to collect trace data](#in-the-apollo-router)). If the subgraph [supports federated traces](#in-your-subgraphs), it attaches tracing information in the `extensions` field of its response. - -## How traces are constructed and aggregated - -Your router constructs traces in the shape of the [query plan](./query-plans/), embedding an individual `Trace` for each fetch that is performed in the query plan. This indicates the sub-query traces, as well as which order they were fetched from the underlying subgraphs. - -The field-level statistics that Apollo aggregates from these traces are collected for the fields over which the operation was executed in the subgraphs. In other words, field stats are collected based on the operations the query planner makes, instead of the operations that the clients make. On the other hand, operation-level statistics are aggregated over the operations executed by the client, which means that even if query-planning changes, statistics still correspond to the same client-delivered operation. - -## How errors work - -The Apollo Platform provides functionality to modify error details for the client, via the [`formatError`](/apollo-server/data/errors#for-client-responses) option. Additionally, there is functionality to support modifying error details for the metrics ingress, via the [`sendErrors`](/apollo-server/data/errors#for-apollo-studio-reporting) option to the [inline trace plugin](/apollo-server/api/plugin/inline-trace/). - -When modifying errors for the client, you might want to use this option to hide implementation details, like database errors, from your users. When modifying errors for reporting, you might want to obfuscate or redact personal information, like user IDs or emails. - -Since federated metrics collection works by collecting latency and error information from a set of distributed subgraphs, these options are respected from those subgraphs as well as from the router. Subgraphs embed errors in their `ftv1` extension after the `rewriteError` method (passed to the inline trace plugin in the subgraph, not the usage reporting plugin in the gateway!) is applied, and the gateway only reports the errors that are sent via that extension, ignoring the format that downstream errors are reported to end users. This functionality enables subgraph implementers to determine how error information should be displayed to both users and in metrics without needing the gateway to contain any logic that might be subgraph-specific. diff --git a/docs/source/metrics.mdx b/docs/source/metrics.mdx deleted file mode 100644 index c5d434c93..000000000 --- a/docs/source/metrics.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: Federated Trace Data -subtitle: Reporting fine-grained performance metrics -description: Explore how federated traces enable fine-grained performance metrics reporting. Learn about the reporting flow and how tracing data is exposed and aggregated. ---- - -One of the many benefits of using GraphQL as an API layer is that it enables fine-grained, field-level [tracing](/graphos/metrics/#resolver-level-traces) of every executed operation. The [GraphOS platform](/graphos/) can consume and aggregate these traces to provide detailed insights into your supergraph's usage and performance. - -Your supergraph's router can generate _federated traces_ and [report them to GraphOS](/graphos/metrics/sending-operation-metrics). A federated trace is assembled from timing and error information provided by each subgraph that helps resolve a particular operation. - -## Reporting flow - -The overall flow of a federated trace is as follows: - -1. The router receives an operation from a client. -2. The router generates a [query plan](/federation/query-plans) for the operation and delegates sub-queries to individual subgraphs. -3. Each queried subgraph returns response data to the router. - - The `extensions` field of each response includes trace data for the corresponding sub-query. - - The subgraph must support the federated trace format to include trace data in its response. See [this section](#in-your-subgraphs). -4. The router collects the set of sub-query traces from subgraphs and arranges them in the shape of the query plan. -5. The router [reports the federated trace to GraphOS](/graphos/metrics/sending-operation-metrics/) for processing. - -In summary, subgraphs report timing and error information to the router, and the router is responsible for aggregating those metrics and reporting them to GraphOS. - -## Enabling federated tracing - -### In your subgraphs - -For a subgraph to include trace data in its responses to your router, it must use a subgraph-compatible library that supports the trace format. - -To check whether your subgraph library supports federated tracing, see the `FEDERATED TRACING` entry for the library on [this page](/federation/building-supergraphs/supported-subgraphs/). - -If your library does support federated tracing, see its documentation to learn how to enable the feature. - - - -If your subgraph uses Apollo Server with `@apollo/subgraph`, federated tracing is enabled by default. You can customize this behavior with Apollo Server's [inline trace plugin](/apollo-server/api/plugin/inline-trace). - - - -### In the Apollo Router - -See [Sending Apollo Router usage data to GraphOS](/router/configuration/telemetry/apollo-telemetry). - -### In `@apollo/gateway` - -You can use the `@apollo/server` package's [built-in usage reporting plugin](/apollo-server/api/plugin/usage-reporting) to enable federated tracing for your gateway. Provide an API key to your gateway via the `APOLLO_KEY` environment variable for the gateway to report metrics to the default ingress. To ensure that subgraphs do not report metrics as well, either do not provide them with an `APOLLO_KEY` or install the [`ApolloServerPluginUsageReportingDisabled` plugin](https://www.apollographql.com/docs/apollo-server/api/plugin/usage-reporting/) in your `ApolloServer`. - -These options will cause the Apollo gateway to collect tracing information from the underlying subgraphs and pass them on, along with the query plan, to the Apollo metrics ingress. - - - -By default, metrics are reported to the `current` GraphOS variant. To change the variant for reporting, set the `APOLLO_GRAPH_VARIANT` environment variable. - - - -## How tracing data is exposed from a subgraph - - - -This section explains how your router communicates with subgraphs around encoded tracing information. It is not necessary to understand in order to enable federated tracing. - - - -Your router inspects the `extensions` field of all subgraph responses for the presence of an `ftv1` field. This field contains a representation of the tracing information for the sub-query that was executed against the subgraph, sent as the Base64 encoding of the [protobuf representation](https://github.com/apollographql/apollo-server/blob/main/packages/usage-reporting-protobuf/src/reports.proto) of the trace. - -To obtain this information from a subgraph, the router includes the header pair `'apollo-federation-include-trace': 'ftv1'` in its request (if it's [configured to collect trace data](#in-the-apollo-router)). If the subgraph [supports federated traces](#in-your-subgraphs), it attaches tracing information in the `extensions` field of its response. - -## How traces are constructed and aggregated - -Your router constructs traces in the shape of the [query plan](/federation/query-plans/), embedding an individual `Trace` for each fetch that is performed in the query plan. This indicates the sub-query traces, as well as which order they were fetched from the underlying subgraphs. - -The field-level statistics that Apollo aggregates from these traces are collected for the fields over which the operation was executed in the subgraphs. In other words, field stats are collected based on the operations the query planner makes, instead of the operations that the clients make. On the other hand, operation-level statistics are aggregated over the operations executed by the client, which means that even if query-planning changes, statistics still correspond to the same client-delivered operation. - -## How errors work - -The Apollo Platform provides functionality to modify error details for the client, via the [`formatError`](/apollo-server/data/errors#for-client-responses) option. Additionally, there is functionality to support modifying error details for the metrics ingress, via the [`sendErrors`](/apollo-server/data/errors#for-apollo-studio-reporting) option to the [inline trace plugin](/apollo-server/api/plugin/inline-trace/). - -When modifying errors for the client, you might want to use this option to hide implementation details, like database errors, from your users. When modifying errors for reporting, you might want to obfuscate or redact personal information, like user IDs or emails. - -Since federated metrics collection works by collecting latency and error information from a set of distributed subgraphs, these options are respected from those subgraphs as well as from the router. Subgraphs embed errors in their `ftv1` extension after the `rewriteError` method (passed to the inline trace plugin in the subgraph, not the usage reporting plugin in the gateway!) is applied, and the gateway only reports the errors that are sent via that extension, ignoring the format that downstream errors are reported to end users. This functionality enables subgraph implementers to determine how error information should be displayed to both users and in metrics without needing the gateway to contain any logic that might be subgraph-specific. diff --git a/docs/source/migrating-from-stitching.md b/docs/source/migrating-from-stitching.md deleted file mode 100644 index 39d9dddc3..000000000 --- a/docs/source/migrating-from-stitching.md +++ /dev/null @@ -1,188 +0,0 @@ ---- -title: Migrating from Schema Stitching -subtitle: How to transition to Apollo Federation -description: Learn how to smoothly transition from schema stitching to Apollo Federation for your distributed federated GraphQL services. ---- - -If you have a distributed graph that uses schema stitching, follow the -steps in this guide to migrate it to use Apollo Federation. - - - -For a real-world example of an organization benefiting from this migration, see [this blog post](https://www.apollographql.com/blog/announcement/expedia-improved-performance-by-moving-from-schema-stitching-to-apollo-federation/). - - - -## Summary of steps - -This guide describes a set of steps for migrating architecture incrementally from stitching to federation. In order to do so, we rely on the fact that changes necessary for federation are completely backwards compatible. Services that implement a part of your graph, also known as _subgraphs_, can be used in both your stitching gateway and your Apollo gateway. - -We recommend that you begin by modifying existing subgraphs in place to support the federation specification while continuing to support schema stitching as well. At this point, you can stand up an Apollo gateway side-by-side with your existing stitching gateway and migrate over the links between the subgraphs in an incremental, backward compatible way. - -Here are the high-level steps for migrating to Apollo Federation: - -1. Add federation support to your subgraphs. -2. Register your GraphQL schemas with a registry. -3. Start up an instance of Apollo Server as a gateway. -4. Migrate stitching logic from your schema-stitching gateway to your subgraphs. -5. Move traffic from the schema-stitching gateway to the Apollo Server gateway. -6. Remove schema-stitching fields from your federated schema and complete your migration. - -Each step is described in detail below. - -[This GitHub repository](https://github.com/apollographql/federation-migration-example) shows the same project before and after migrating to Apollo Federation from schema stitching. - -## Step 1: Add federation support to your subgraphs - -You can add federation support to your subgraphs without impacting your existing schema-stitching architecture. Support for federation is fully compatible with schema stitching. - -Because of this, we recommend that you migrate your subgraphs in-place instead of creating replacement subgraphs. Doing so helps you identify any type conflicts that exist across your graph. - -### Using Apollo Server - -If your subgraphs use Apollo Server, add federation support to them by installing the `@apollo/subgraph` package: - -```bash -npm install @apollo/subgraph -``` - -Then use the `buildSubgraphSchema` function to augment your schema with fields that are necessary for federation support: - -```js -const { ApolloServer } = require('@apollo/server'); -const { buildSubgraphSchema } = require('@apollo/subgraph'); - -const server = new ApolloServer({ - schema: buildSubgraphSchema([ - { - typeDefs, - resolvers, - }, - ]), -}); -``` - -### Using a GraphQL server besides Apollo Server - -There are [several community-contributed packages](./building-supergraphs/supported-subgraphs/) that add federation support to other GraphQL runtimes. - -## Step 2: Register your schemas with a GraphQL registry - -We strongly recommend that you register all of your GraphQL schemas with an [external registry](https://principledgraphql.com/integrity#3-track-the-schema-in-a-registry). This registry supports running the gateway with the subgraphs' partial schemas. Additionally, it enables tracking changes at the subgraph level and protecting the graph from changes that break composition. - -[GraphOS](/graphos#whats-in-graphos) provides a free schema registry that helps you manage your federated gateway's configuration. You provide your gateway a Studio API key on startup, which directs the gateway to download your schemas automatically in a fault-tolerant way. - -GraphOS can also provide [schema validation](/graphos/platform/schema-management/checks/) to ensure that all changes you make to your subgraphs are compatible with your complete graph. - -[Learn more about managed configuration.](./managed-federation/overview) - -## Step 3: Start up an Apollo Server gateway - -After you've registered your schemas, you can start exposing your subgraphs from a federation-compatible gateway. Apollo Server's gateway is a query planner and executor that handles incoming GraphQL requests and breaks them down into a collection of operations to perform on your subgraphs. - -We recommend setting up the Apollo Server gateway alongside your existing schema-stitching gateway. Depending on your infrastructure, you might even want to run both in the same process to support dynamically routing traffic through one gateway or the other. - -To enable managed configuration with GraphOS Studio, set the `APOLLO_KEY` and `APOLLO_GRAPH_REF` environment variables when you start up your Apollo Server gateway, and do not provide the `supergraphSDL` or `serviceList` constructor option to `ApolloGateway`. For details, see the [managed federation documentation](./managed-federation/overview). - -After your gateway is set up, you can make direct queries to it that are routed to the correct subgraphs. - -## Step 4: Move linking logic to your subgraphs - -When using a schema-stitching gateway, your linking logic typically resides in the gateway itself. In the federation model, however, linking logic resides in each subgraph. Therefore, you need to migrate linking logic from your schema-stitching gateway into each of your subgraphs. - -Here are recommendations for common cases when migrating your logic: - -* **Fragments**: Fragments in a schema-stitching resolver, usually translate to a combination of `@key` and `@requires` directives in a federated model. In general, think of `@key` as the field(s) that completely identify an entity, and only use `@requires` for additional, non-identifying information. -* **Filtering types**: We do not recommend filtering types out of your exposed schema when using a gateway. If you want to hide types, do not include them in your subgraph's registered schema. -* **Renaming types**: If you are currently renaming types at the gateway level, rename these types at the subgraph level instead. -* **Transforming fields**: If you are currently transforming fields at the gateway level, transform these fields at the subgraph level instead. - -### Adding resolvers to your subgraphs - -At this point your subgraphs support federation, but they still need to be able to resolve extensions to types that are defined in other subgraphs. - -A schema-stitching architecture declares this logic at the gateway level using the `delegateToSchema` function, like so: - -```js -resolvers: { - Reservation: { - user: { - fragment: `... on Reservation { userId }`, - resolve: (parent, args, context, info) => { - return info.mergeInfo.delegateToSchema({ - schema: userSchema, - operation: 'query', - fieldName: 'user', - args: { - id: parent.userId, - }, - context, - info, - }); - }, - }, - }, -} -``` - -This resolver calls `Query.user` on the `userSchema` to look up a `User`. It adds that user to the `Reservation.user` field that was previously defined at the gateway. This code can all remain. You don't need to remove it from the stitched gateway. In fact, if you did that, the stitched gateway would break. - -On the other hand, a federated architecture defines its resolvers at the subgraph level. These resolvers rely on entities, which are identified by a unique key. For example, the Reservation subgraph must define the `Reservation` type as an entity to allow other subgraphs to extend it. These other subgraphs use the `Reservation`'s `@key` fields to uniquely identify a given instance: - -```graphql -type Reservation @key(fields: "id") { - id: ID! - ... -} -``` - -In the Users subgraph, you can then extend the `Reservation` type with a `user` field like so: - -```graphql -extend type Reservation @key(fields: "id") { - id: ID! @external - userId: ID! @external - user: User @requires(fields: "userId") -} -``` - -The `user` field indicates that it `@requires` a `Reservation`'s `userId` field in order to identify the user that made the reservation. - -Then in the Users subgraph, you can add a resolver for `Reservation.user` like so: - -```js -{ - Reservation: { - user: ({ userId }) => { - return lookupUser(userId); - }, - } -} -``` - -Federated resolvers like this one always receive an object that represents an instance of the extended entity. This object includes the fields that are part of the entity's `@key`, along with any other fields that the resolver `@requires`. - -For example, this `Reservation.user` resolver receives the `id` of the reservation and a `userId`. You can use the `userId` to look up the corresponding user. - -## Step 5: Move traffic from the schema-stitching gateway to the Apollo Server gateway - -At this point, both your schema-stitching gateway and your federated gateway are able to resolve GraphQL operations. You can now begin moving traffic from the schema-stitching gateway to the federated gateway. - -Perform this migration in the manner that best suits your infrastructure and applications. - -Some options include: - -* Testing a complete migration in your staging environment to verify that both gateways behave identically -* Use HTTP headers or feature flags to migrate your internal clients without affecting your user-facing clients - -## Step 6: Remove schema-stitching fields from your federated schema - -After you've fully migrated your graph and incoming traffic to use your federated gateway, you can remove all stitching-specific logic from your architecture. - -You can now begin to modify your existing schema to take full advantage of the -features that federation provides. These features include: - -* Greater flexibility with [federation core concepts](./) -* [Metrics and analysis of query plans](./performance/monitoring/#metrics-and-observability) -* [Gateway support for live schema updates](./managed-federation/deployment/#the-subgraph-publish-lifecycle) -* [Validation of composition logic and usage traffic](./managed-federation/federated-schema-checks/) diff --git a/docs/source/building-supergraphs/compatible-subgraphs.mdx b/docs/source/reference/federation/compatible-subgraphs.mdx similarity index 95% rename from docs/source/building-supergraphs/compatible-subgraphs.mdx rename to docs/source/reference/federation/compatible-subgraphs.mdx index 813735cdd..96152d9b9 100644 --- a/docs/source/building-supergraphs/compatible-subgraphs.mdx +++ b/docs/source/reference/federation/compatible-subgraphs.mdx @@ -12,7 +12,7 @@ The following open-source GraphQL server libraries and hosted solutions support | Icon | Description | | --- | --- | -| Maintained by Apollo | Maintained by Apollo | +| Maintained by Apollo | Maintained by Apollo | | 🟒 | Functionality is supported | | ❌ | Critical functionality is NOT supported | | πŸ”² | Additional federation functionality is NOT supported | @@ -36,7 +36,7 @@ The following open-source GraphQL server libraries and hosted solutions support A spec-compliant, production-ready, Standard Library module for building and interacting with GraphQL APIs using Ballerina.

- Github: ballerina-platform/module-ballerina-graphql

+ GitHub: ballerina-platform/module-ballerina-graphql

Type: Code first
Stars: 144 ⭐
Last Release: 2024-05-03

@@ -91,7 +91,7 @@ The following open-source GraphQL server libraries and hosted solutions support GraphQL for .NET

- Github: graphql-dotnet/graphql-dotnet

+ GitHub: graphql-dotnet/graphql-dotnet

Type: Code first | SDL first
Stars: 5.8k ⭐
Last Release: 2024-02-06

@@ -132,7 +132,7 @@ The following open-source GraphQL server libraries and hosted solutions support Open-source GraphQL server for the Microsoft .NET platform that takes the complexity away and lets you focus on delivering the next big thing.

- Github: ChilliCream/graphql-platform

+ GitHub: ChilliCream/graphql-platform

Type: Code first | SDL first
Stars: 4.9k ⭐
Last Release: 2024-04-22

@@ -188,7 +188,7 @@ The following open-source GraphQL server libraries and hosted solutions support The GraphQL toolkit for Elixir

-Github: absinthe-graphql/absinthe
+GitHub: absinthe-graphql/absinthe

Type: Code first
Stars: 4.2k ⭐
@@ -245,7 +245,7 @@ Federation Library: go generate based graphql server library

-Github:
99designs/gqlgen
+GitHub: 99designs/gqlgen

Type: SDL first
Stars: 9.6k ⭐
@@ -287,7 +287,7 @@ Last Release: 2024-03-11
This is a fork of graphql-go/graphql that adds Federation support

-Github: dariuszkuc/graphql
+GitHub: dariuszkuc/graphql

Type: Code first
Stars: 2 ⭐
@@ -343,14 +343,14 @@ Last Release: 2022-11-11
GraphQL for Java with Spring Boot made easy.

-Github: netflix/dgs-framework
+GitHub: netflix/dgs-framework

Type: SDL first
Stars: 3.0k ⭐
Last Release: 2024-04-30

Core Library: GraphQL Java
-Federation Library: apollographql/federation-jvm  Maintained by Apollo +Federation Library: apollographql/federation-jvm  Maintained by Apollo @@ -387,14 +387,14 @@ Federation Library: ap
GraphQL and GraphiQL Spring Framework Boot Starters - Forked from oembedler/graphql-spring-boot due to inactivity.

-Github: graphql-java-kickstart/graphql-spring-boot
+GitHub: graphql-java-kickstart/graphql-spring-boot

Type: SDL first
Stars: 1.5k ⭐
Last Release: 2023-12-07

Core Library: GraphQL Java
-Federation Library: apollographql/federation-jvm  Maintained by Apollo +Federation Library: apollographql/federation-jvm  Maintained by Apollo
@@ -431,7 +431,7 @@ Federation Library: ap
Libraries for running GraphQL in Kotlin

-Github: ExpediaGroup/graphql-kotlin
+GitHub: ExpediaGroup/graphql-kotlin

Type: Code first
Stars: 1.7k ⭐
@@ -474,14 +474,14 @@ Core Library: GraphQL Jav
Spring Integration for GraphQL

-Github: spring-projects/spring-graphql
+GitHub: spring-projects/spring-graphql

Type: SDL first
Stars: 1.5k ⭐
Last Release: 2024-04-16

Core Library: GraphQL Java
-Federation Library: apollographql/federation-jvm  Maintained by Apollo +Federation Library: apollographql/federation-jvm  Maintained by Apollo
@@ -532,14 +532,14 @@ Federation Library: ap
🌍  Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.

-Github: apollographql/apollo-server  Maintained by Apollo
+GitHub: apollographql/apollo-server  Maintained by Apollo

Type: SDL first
Stars: 13.7k ⭐
Last Release: 2024-04-18

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -576,14 +576,14 @@ Federation Library: Apo
Create a GraphQL HTTP server with Express.

-Github: graphql/express-graphql
+GitHub: graphql/express-graphql

Type: SDL first
Stars: 6.3k ⭐
Last Release: 2020-11-19

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -618,16 +618,16 @@ Federation Library: Apo
- The fully-featured GraphQL server with focus on easy setup, performance and great developer experience.
+ The fully featured GraphQL server with focus on easy setup, performance and great developer experience.

-Github: dotansimha/graphql-yoga
+GitHub: dotansimha/graphql-yoga

Type: SDL first
Stars: 8.0k ⭐
Last Release: 2024-03-29

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -664,14 +664,14 @@ Federation Library: Apo
A highly evolved and framework-agnostic GraphQL HTTP server.

-Github: contra/graphql-helix
+GitHub: contra/graphql-helix

Type: SDL first
Stars: 831 ⭐
Last Release: 2022-07-09

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -708,14 +708,14 @@ Federation Library: Apo
Implement GraphQL servers and gateways with Fastify

-Github: mercurius-js/mercurius
+GitHub: mercurius-js/mercurius

Type: SDL first
Stars: 2.3k ⭐
Last Release: 2024-04-22

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -752,14 +752,14 @@ Federation Library: Apo
A progressive Node.js framework for building efficient, reliable and scalable server-side applications.

-Github: nestjs/graphql
+GitHub: nestjs/graphql

Type: Code first
Stars: 1.4k ⭐
Last Release: 2024-02-07

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -796,14 +796,14 @@ Federation Library: Apo
A progressive Node.js framework for building efficient, reliable and scalable server-side applications.

-Github: nestjs/graphql
+GitHub: nestjs/graphql

Type: SDL first
Stars: 1.4k ⭐
Last Release: 2024-02-07

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
@@ -840,7 +840,7 @@ Federation Library: Apo
Plugin based GraphQL schema builder that makes building graphql schemas with TypeScript easy, fast and enjoyable.

-Github: hayes/pothos
+GitHub: hayes/pothos

Type: Code first
Stars: 2.2k ⭐
@@ -897,7 +897,7 @@ Core Library: GraphQL.js
A framework for serving GraphQL from Laravel

-Github: nuwave/lighthouse
+GitHub: nuwave/lighthouse

Type: SDL first
Stars: 3.3k ⭐
@@ -940,7 +940,7 @@ Core Library: webonyx/graphql-p
PHP implementation of the GraphQL specification based on the reference implementation in JavaScript

-Github: webonyx/graphql-php
+GitHub: webonyx/graphql-php

Type: Code first
Stars: 4.6k ⭐
@@ -997,7 +997,7 @@ Federation Library: mirumee/ariadne
+GitHub: mirumee/ariadne

Type: SDL first
Stars: 2.1k ⭐
@@ -1040,7 +1040,7 @@ Core Library: GraphQL-c
GraphQL framework for Python

-Github: graphql-python/graphene
+GitHub: graphql-python/graphene

Type: Code first
Stars: 8.0k ⭐
@@ -1084,7 +1084,7 @@ Federation Library: strawberry-graphql/strawberry
+GitHub: strawberry-graphql/strawberry

Type: Code first
Stars: 3.8k ⭐
@@ -1141,7 +1141,7 @@ Core Library: GraphQL-c
Ruby implementation of GraphQL

-Github: rmosolgo/graphql-ruby
+GitHub: rmosolgo/graphql-ruby

Type: Code first
Stars: 5.3k ⭐
@@ -1198,7 +1198,7 @@ Federation Library: G
A GraphQL server library implemented in Rust

-Github: async-graphql/async-graphql
+GitHub: async-graphql/async-graphql

Type: Code first
Stars: 3.2k ⭐
@@ -1254,7 +1254,7 @@ Last Release: 2022-11-28
Functional GraphQL library for Scala

-Github: ghostdogpr/caliban
+GitHub: ghostdogpr/caliban

Type: Code first
Stars: 939 ⭐
@@ -1296,7 +1296,7 @@ Last Release: 2024-04-16
Scala GraphQL implementation

-Github: sangria-graphql/sangria
+GitHub: sangria-graphql/sangria

Type: Code first
Stars: 2.0k ⭐
@@ -1353,7 +1353,7 @@ Federation Library: GraphQLSwift/Graphiti
+GitHub: GraphQLSwift/Graphiti

Type: SDL first
Stars: 523 ⭐
@@ -1483,7 +1483,7 @@ Last Release: 2023-11-15
The GraphQL platform

-Github: grafbase/grafbase
+GitHub: grafbase/grafbase

Type: Code first | SDL first
Stars: 934 ⭐
@@ -1525,7 +1525,7 @@ Last Release: 2024-02-23
Executable GraphQL schema from multiple data sources, query anything, run anywhere.

-Github: Urigo/graphql-mesh
+GitHub: Urigo/graphql-mesh

Stars: 3.2k ⭐
@@ -1567,14 +1567,14 @@ Last Release: 2024-04-30
A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations.

-Github: neo4j/graphql
+GitHub: neo4j/graphql

Type: Code first | SDL first
Stars: 485 ⭐
Last Release: 2024-04-30

Core Library: GraphQL.js
-Federation Library: Apollo Subgraph  Maintained by Apollo +Federation Library: Apollo Subgraph  Maintained by Apollo
diff --git a/docs/source/reference/federation/composition-rules.mdx b/docs/source/reference/federation/composition-rules.mdx new file mode 100644 index 000000000..9d852077a --- /dev/null +++ b/docs/source/reference/federation/composition-rules.mdx @@ -0,0 +1,470 @@ +--- +title: Composition Rules +subtitle: Learn what rules subgraph schemas must follow to successfully compose +description: Learn what rules subgraph schemas must follow to successfully compose in a federated GraphQL architecture. +redirectFrom: + - /federation/federated-types/composition/#rules-of-composition + - /federation/federated-schemas/composition/#rules-of-composition +--- + +In Federation 2, your subgraph schemas must follow all of these rules to successfully compose into a supergraph schema: + +- Multiple subgraphs can't define the same field on an object type, unless that field is [shareable](/graphos/schema-design/federated-schemas/sharing-types#using-shareable). +- A shared field must have both a compatible return type and compatible argument types across each defining subgraph. + - For examples of compatible and incompatible differences between subgraphs, see [Differing shared fields](/graphos/schema-design/federated-schemas/sharing-types#differing-shared-fields). +- If multiple subgraphs define the same type, each field of that type must be resolvable by every valid GraphQL operation that includes it. + - This rule is the most complex and the most essential to Federation 2. [Let's look at it more closely.](#unresolvable-field-example) + +### Unresolvable field example + +This example presents a field of a shared type that is not always resolvable (and therefore [breaks composition](#breaking-composition)). + +Consider these subgraph schemas: + +

❌

+ + + +```graphql title="Subgraph A" +type Query { + positionA: Position! +} + +type Position @shareable { + x: Int! + y: Int! +} +``` + +```graphql title="Subgraph B" +type Query { + positionB: Position! +} + +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + + + + +Note the following about these two subgraphs: + +- They both define a shared `Position` type. +- They both define a top-level `Query` field that returns a `Position`. +- Subgraph B's `Position` includes a `z` field, whereas Subgraph A's definition only includes shared `x` and `y` fields. + +Individually, these subgraph schemas are perfectly valid. However, if they're combined, they break composition. Why? + +The composition process attempts to merge inconsistent type definitions into a single definition for the supergraph schema. In this case, the resulting definition for `Position` exactly matches Subgraph B's definition: + +

❌

+ +```graphql title="Hypothetical supergraph schema" +type Query { + # From A + positionA: Position! + # From B + positionB: Position! +} + +type Position { + # From A+B + x: Int! + y: Int! + # From B + z: Int! +} +``` + +Based on this hypothetical supergraph schema, the following query should be valid: + +```graphql {5} +query GetPosition { + positionA { + x + y + z # ⚠️ Can't be resolved! ⚠️ + } +} +``` + +Here's our problem. Only Subgraph A can resolve `Query.positionA`, because Subgraph B doesn't define the field. But Subgraph A doesn't define `Position.z`! + +If the router sent this query to Subgraph A, it would return an error. And without extra configuration, Subgraph B can't resolve a `z` value for a `Position` in Subgraph A. Therefore, `Position.z` is unresolvable for this query. + +Composition recognizes this potential issue, and it fails. The hypothetical supergraph schema above would never actually be generated. + +`Position.z` is an example of a field that is not always resolvable. Refer to the following section for solutions. + +### Solutions for unresolvable fields + +There are multiple solutions for making sure that a field of a shared type is always resolvable. Choose a solution based on your use case: + +#### Define the field in every subgraph that defines the type + +If every subgraph that defines a type could resolve every field of that type without introducing complexity, a straightforward solution is to define and resolve all fields in all of those subgraphs: + +

βœ…

+ + + +```graphql {4} title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! + z: Int +} +``` + +```graphql title="Subgraph B" +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + + + +In this case, if Subgraph A only cares about the `x` and `y` fields, its resolver for `z` can always return `null`. + +This is a useful solution for shared types that encapsulate simple scalar data. + + + +You can use the `@inaccessible` directive to incrementally add a value type field to multiple subgraphs without breaking composition. [Learn more.](/graphos/schema-design/federated-schemas/sharing-types#adding-new-shared-fields) + + + +#### Make the shared type an entity + +

βœ…

+ + + +```graphql title="Subgraph A" +type User @key(fields: "id") { + id: ID! + name: String! +} +``` + +```graphql title="Subgraph B" +type User @key(fields: "id") { + id: ID! + age: Int! +} +``` + + + +If you make a shared type an [entity](/graphos/schema-design/federated-schemas/entities/intro), different subgraphs can define any number of different fields for that type, as long as they all define key fields for it. + +This is a useful solution when a type corresponds closely to an entry in a data store that one or more of your subgraphs has access to (for example, a `Users` database). + +## Merging types from multiple subgraphs + +If a particular GraphQL type is defined differently by different subgraphs, composition uses one of two strategies to merge those definitions: _union_ or _intersection_. + +- **Union**: The supergraph schema includes all parts of all subgraph definitions for the type. +- **Intersection**: The supergraph schema includes only the parts of the type that are present in every subgraph that defines the type. + +The merging strategy that composition uses for a particular type depends on the type, as described below. + +### Object, union, and interface types + +Composition always uses the union strategy to merge object, union, and interface types. + +Consider the following subgraph schemas: + + + +```graphql title="Subgraph A" +type User @key(fields: "id") { + id: ID! + name: String! + email: String! +} + +union Media = Book | Movie + +interface BookDetails { + title: String! + author: String! +} +``` + +```graphql title="Subgraph B" +type User @key(fields: "id") { + id: ID! + age: Int! +} + +union Media = Book | Podcast + +interface BookDetails { + title: String! + numPages: Int +} +``` + + + +When these subgraph schemas are composed, the composition process merges the three corresponding types by union. This results in the following type definitions in the supergraph schema: + +```graphql title="Supergraph schema" +type User { + id: ID! + age: Int! + name: String! + email: String! +} + +union Media = Book | Movie | Podcast + +interface BookDetails { + title: String! + author: String! + numPages: Int +} +``` + +Because composition uses the union strategy for these types, subgraphs can contribute distinct parts and guarantee that those parts will appear in the composed supergraph schema. + + + +If different subgraphs contribute different fields to an interface type, any object types that implement that interface must define all contributed fields from all subgraphs. Otherwise, composition fails. + + + +### Input types and field arguments + +Composition always uses the intersection strategy to merge input types and field arguments. This ensures that the router never passes an argument to a subgraph that doesn't define that argument. + +Consider the following subgraph schemas: + + + +```graphql title="Subgraph A" +input UserInput { + name: String! + age: Int +} + +type Library @shareable { + book(title: String, author: String): Book +} +``` + +```graphql title="Subgraph B" +input UserInput { + name: String! + email: String +} + +type Library @shareable { + book(title: String, section: String): Book +} +``` + + + +These subgraphs define different fields for the `UserInput` input type, and they define different arguments for the `Library.book` field. After composition merges using intersection, the supergraph schema definitions look like this: + +```graphql title="Supergraph schema" +input UserInput { + name: String! +} + +type Library { + book(title: String): Book +} +``` + +As you can see, the supergraph schema includes only the input fields and arguments that both subgraphs define. + + + +If the intersection strategy would omit an input field or argument that is non-nullable, composition fails. This is because at least one subgraph requires that field or argument, and the router can't provide it if it's omitted from the supergraph schema. + +When defining input types and field arguments in multiple subgraphs, make sure that every non-nullable field and argument is consistent in every subgraph. For examples, see [Arguments](/graphos/schema-design/federated-schemas/sharing-types#arguments). + + + +### Enums + +If an enum definition differs between subgraphs, the [composition strategy](#merging-types-from-multiple-subgraphs) depends on how the enum is used: + +| Scenario | Strategy | +|----------|----------| +| The enum is used as the return type for at least one object or interface field. | [Union](#union) | +| The enum is used as the type for at least one field argument or input type field. | [Intersection](#intersection) | +| Both of the above are true. | All definitions must [match exactly](#exact-match) | + +Examples of these scenarios are provided below. + +#### Enum composition examples + +##### Union + +Consider these subgraph schemas: + + + +```graphql title="Subgraph A" +enum Color { + RED + GREEN + BLUE +} + +type Query { + favoriteColor: Color +} +``` + +```graphql title="Subgraph B" +enum Color { + RED + GREEN + YELLOW +} + +type Query { + currentColor: Color +} +``` + + + +In this case, the `Color` enum is used as the return type of at least one object field. Therefore, composition merges the `Color` enum by union, so that all possible subgraph return values are valid. + +This results in the following type definition in the supergraph schema: + +```graphql title="Supergraph schema" +enum Color { + RED + GREEN + BLUE + YELLOW +} +``` + +##### Intersection + +Consider these subgraph schemas: + + + +```graphql title="Subgraph A" +enum Color { + RED + GREEN + BLUE +} + +type Query { + products(color: Color): [Product] +} +``` + +```graphql title="Subgraph B" +enum Color { + RED + GREEN + YELLOW +} + +type Query { + images(color: Color): [Image] +} +``` + + + +In this case, the `Color` enum is used as the type of at least one field argument (or input type field). Therefore, composition merges the `Color` enum by intersection, so that subgraphs never receive a client-provided enum value that they don't support. + +This results in the following type definition in the supergraph schema: + +```graphql title="Supergraph schema" +# BLUE and YELLOW are removed via intersection +enum Color { + RED + GREEN +} +``` + +##### Exact match + +Consider these subgraph schemas: + +

❌

+ + + +```graphql title="Subgraph A" +enum Color { + RED + GREEN + BLUE +} + +type Query { + favoriteColor: Color +} +``` + +```graphql title="Subgraph B" +enum Color { + RED + GREEN + YELLOW +} + +type Query { + images(color: Color): [Image] +} +``` + + + +In this case, the `Color` enum is used as both: + +- The return type of at least one object field +- The type of at least one field argument (or input type field) + +Therefore, the definition of the `Color` enum must match exactly in every subgraph that defines it. An exact match is the only scenario that enables union and intersection to produce the same result. + +The subgraph schemas above do not compose, because their definitions of the `Color` enum differ. + +## Directives + +Composition handles a directive differently depending on whether it's an "executable" directive or a "type system" directive. + +### Executable directives + +Executable directives are intended to be used by clients in their queries. They are applied to one or more of the [executable directive locations](http://spec.graphql.org/June2018/#ExecutableDirectiveLocation). For example, you might have a directive definition of `directive @lowercase on FIELD`, which a client could use in their query like so: + +```graphql +query { + getSomeData { + someField @lowercase + } +} +``` + +An executable directive is composed into the supergraph schema only if all of the following conditions are met: + +- The directive is defined in all subgraphs. +- The directive is defined identically in all subgraphs. +- The directive is not included in any [`@composeDirective`](/graphos/reference/federation/directives#composedirective) directives. + +### Type system directives + +Type system directives help define the structure of the schema and are not intended for use by clients. They are applied to one or more of the [type system directive locations](http://spec.graphql.org/June2018/#TypeSystemDirectiveLocation). + +These directives are not composed into the supergraph schema, but they can still provide information to the router via the [`@composeDirective`](/graphos/reference/federation/directives#composedirective) directive. diff --git a/docs/source/federated-schemas/federated-directives.mdx b/docs/source/reference/federation/directives.mdx similarity index 99% rename from docs/source/federated-schemas/federated-directives.mdx rename to docs/source/reference/federation/directives.mdx index 763eabe69..8ad0733bc 100644 --- a/docs/source/federated-schemas/federated-directives.mdx +++ b/docs/source/reference/federation/directives.mdx @@ -4,8 +4,8 @@ subtitle: Reference for Apollo Federation specific GraphQL directives description: Reference for GraphQL federation directives including @key, @extends, @sharable, @override, @requires and more. --- -import ProgressiveOverrideEnterprise from '../../shared/progressive-override-enterprise.mdx'; -import EnterpriseDirective from '../../shared/enterprise-directive.mdx'; +import ProgressiveOverrideEnterprise from '../../../shared/progressive-override-enterprise.mdx'; +import EnterpriseDirective from '../../../shared/enterprise-directive.mdx'; Apollo Federation defines a collection of directives that you use in your subgraph schemas to enable certain features. diff --git a/docs/source/errors.mdx b/docs/source/reference/federation/errors.mdx similarity index 100% rename from docs/source/errors.mdx rename to docs/source/reference/federation/errors.mdx diff --git a/docs/source/hints.mdx b/docs/source/reference/federation/hints.mdx similarity index 100% rename from docs/source/hints.mdx rename to docs/source/reference/federation/hints.mdx diff --git a/docs/source/building-supergraphs/jetbrains-ide-support.mdx b/docs/source/reference/federation/jetbrains-ide-support.mdx similarity index 96% rename from docs/source/building-supergraphs/jetbrains-ide-support.mdx rename to docs/source/reference/federation/jetbrains-ide-support.mdx index f6c306c18..2fa9f5d4b 100644 --- a/docs/source/building-supergraphs/jetbrains-ide-support.mdx +++ b/docs/source/reference/federation/jetbrains-ide-support.mdx @@ -18,7 +18,7 @@ To enable federation support, do the following in your IDE after installing the An animation showing the process of enabling Apollo Federation support in the GraphQL plugin for JetBrains (described above) diff --git a/docs/source/query-plans.mdx b/docs/source/reference/federation/query-plans.mdx similarity index 100% rename from docs/source/query-plans.mdx rename to docs/source/reference/federation/query-plans.mdx diff --git a/docs/source/subgraph-spec.mdx b/docs/source/reference/federation/subgraph-spec.mdx similarity index 100% rename from docs/source/subgraph-spec.mdx rename to docs/source/reference/federation/subgraph-spec.mdx diff --git a/docs/source/building-supergraphs/subgraph-specific-fields.mdx b/docs/source/reference/federation/subgraph-specific-fields.mdx similarity index 100% rename from docs/source/building-supergraphs/subgraph-specific-fields.mdx rename to docs/source/reference/federation/subgraph-specific-fields.mdx diff --git a/docs/source/federation-versions.mdx b/docs/source/reference/federation/versions.mdx similarity index 100% rename from docs/source/federation-versions.mdx rename to docs/source/reference/federation/versions.mdx diff --git a/docs/source/federation-2/backward-compatibility.mdx b/docs/source/reference/migration/backward-compatibility.mdx similarity index 100% rename from docs/source/federation-2/backward-compatibility.mdx rename to docs/source/reference/migration/backward-compatibility.mdx diff --git a/docs/source/reference/migration/from-monolith.mdx b/docs/source/reference/migration/from-monolith.mdx new file mode 100644 index 000000000..d82b12b74 --- /dev/null +++ b/docs/source/reference/migration/from-monolith.mdx @@ -0,0 +1,281 @@ +--- +title: Moving a GraphQL Monolith to Apollo Federation +subtitle: Steps for migrating from a GraphQL monolith to a federated supergraph +description: A step-by-step guide for migrating from a GraphQL monolith to a federated supergraph with Apollo Federation. +published: 2022-09-06 +id: TN0013 +tags: [federation, server] +redirectFrom: + - /technotes/TN0013-monolith-to-federation/ +--- + + + +For a complete, step-by-step tutorial, check out [Voyage II: Federating the monolith](https://www.apollographql.com/tutorials/voyage-part2). + + + +As with any monolithic service, teams can struggle to change and maintain their GraphQL API as it grows larger and receives contributions from more developers. + +Breaking up the monolith into smaller GraphQL APIs might be the right strategy for your team. With Apollo Federation, you can break up a monolith without sacrificing the unified API that your client applications depend on. Each _subgraph_ can be independently updated, deployed, and scaled while contributing to a single unified schema. + +Here are the steps we recommend to convert a monolithic GraphQL API into a federated GraphQL API. + +## Planning and preparation + +### 1. Put a router in front of your existing API + +Start the process by making a "federated graph of one." Your existing monolith can act as a subgraph without any schema changes. + +1. If you're not already publishing your schema to GraphOS Studio, create a new graph in your Studio organization. Choose "Supergraph" for your graph architecture. +1. Publish your monolith schema to GraphOS Studio as a subgraph with the following command (modify your `--routing-url` and `--schema` path as needed): + + ```sh + rover subgraph publish --name monolith \ + --schema ./schema.graphql \ + --routing-url http://monolith.prod.svc.cluster.local/graphql \ + --convert # necessary if you're publishing to an existing variant + ``` + +1. Deploy an instance of the GraphOS Router to your environment. + + + Self-hosting the GraphOS Router is limited to [GraphOS Enterprise plans](https://www.apollographql.com/pricing). Other plan types use [managed cloud routing with GraphOS](/graphos/cloud-routing). Check out the [pricing page](https://www.apollographql.com/pricing/) to learn more. + + +1. Set up [header propagation](/router/configuration/header-propagation/) so that the monolith receives any necessary headers from the router. +1. Set up internal routing rules to redirect client requests to the router instead of your monolith. +1. Enable usage metrics reporting to GraphOS Studio. +1. Add [subgraph checks](/graphos/platform/schema-management/checks/) to your monolith's CI pipeline. + +At this point, client requests go to your new router instead of the monolith, but it's serving the same schema so clients won't know the difference. + +Not only are you prepared to federate your schema, you now have field-level visibility into graph usage and breaking change detection. + +### 2. Identify entities + +Next, look through all the types in your schema and identify possible [entities](/graphos/schema-design/federated-schemas/entities/intro#entity-overview). Entities are types that form the foundation of your data model, and they must include fields that can uniquely identify each instance of them. + +Consider this schema for a travel booking site: + + + +```graphql +type Account { + id: ID! + username: String + user: User + profile: Profile +} + +type Address { + line1: String + line2: String + city: String + state: String + zip: String +} + +type Airline { + id: ID! + name: String +} + +type Airplane { + id: ID! + class: String +} + +type Airport { + code: AirportCode! + airlines: [Airline] +} + +type Amenity { + name: String + description: String + photoUrl: String +} + +type Bed { + id: ID! + size: BedSize + room: Room +} + +type CancellationPolicy { + text: String + updatedAt: DateTime +} + +type Flight { + number: FlightNumber! + airplane: Airplane + origin: Airport + destination: Airport + scheduledTakeoff: DateTime +} + +type Hotel { + id: ID! + name: String + address: Address +} + +type Profile { + name: String + address: Address + phone: String + email: String +} + +type Reservation { + account: Account + flights: [Flight] + hotels: [Hotel] +} + +type Room { + number: ID! + floor: Int + hotel: Hotel +} + +type Seat { + number: ID! + airplane: Airplane +} + +type User { + id: ID! + account: Account + username: String + reservations: [Reservation] +} + +type Query { + me: User + searchHotels(input: SearchHotelInput!): [Hotel] + searchFlights(input: SearchFlightInput!): [Flight] +} +``` + + + +Types such as `User`, `Reservation`, `Flight`, and `Hotel` are uniquely identifiable, whereas `Profile`, ` CancellationPolicy`, and `Amenity` are basically groups of attributes attached to those entities. + +### 3. Group entities + +After you've identified your entities, group them by their logical domain or concern. These groups usually correspond to product boundaries, but they might also be team boundaries. This is how you'll determine how many subgraphs you'll end up with. + +| Accounts domain | Flights domain | Hotels domain | +| --------------- | -------------- | ------------- | +| `Account` | `Airplane` | `Bed` | +| `User` | `Airline` | `Hotel` | +| | `Flight` | `Reservation` | +| | `Reservation` | `Room` | +| | `Seat` | | + +### 4. Rank entities by ease of migration + +When you're deciding how to start migrating types to other subgraphs, it's helpful to consider a few things first: + +#### How many related types will you have to migrate at the same time? + +Count the number of value types associated with an entity. You'll need to copy all those types over to the new subgraph when you migrate the entity. Entities with fewer related scalars, enums, and non-entity object types will be a bit easier to migrate. + +You won't need to move related entities at the same time as long as you can return an [entity reference](/graphos/schema-design/federated-schemas/entities/contribute-fields#referencing-an-entity-without-contributing-fields). For example, you can move the `Room` type if you have access to the `Hotel` foreign key: + +```graphql title="Hotels subgraph" +type Room @key(fields: "number") { + number: ID! + floor: Int + hotel: Hotel +} + +type Hotel @key(fields: "id", resolvable: false) { + id: ID! # comes from rooms.hotel_id in the database +} +``` + +It might be safer and easier to move the entire `Room` type but only a "stub" of the `Hotel` type. The query planner can fetch the rest of the `Hotel` fields from the monolith until you move that type as well. + +#### How complex will your query plans become during the migration? + +If you start by moving a type that's deeply interconnected with other types, you might introduce unnecessary complexity to your router's query plans. For example, consider this query: + +```graphql +query MyFlights { + me { + reservations { + flights { + ...FlightDetails + } + } + } +} +``` + +This query returns a list of `Reservation` objects belonging to a particular `User`, and each `Reservation` contains a list of `Flight`s. If you start by moving the `Reservation` type to another subgraph, this query results in an "A→B→A" query plan (fetching the `User`, then the `Reservation`, then the `Flight` in three serial subgraph fetches): + +```mermaid +flowchart TD + A(monolith) --> B(subgraph) + B --> C(monolith) +``` + +A better choice at this stage might be to move the `Flight` type so that the query plan is much more efficient, fetching both the `User` and `Reservation` together before fetching the `Flight`: + +```mermaid +flowchart TD + A(monolith) --> B(subgraph) +``` + +When you move a type to another subgraph, you should also move all root-level fields that return that type (such as `Query.flight(id:)`. This way, objects of that type can be returned with only a single subgraph operation in the best case. And in the general case, the query plan can fetch any additional data with fewer total subgraph operations: + +```mermaid +flowchart TD + A(subgraph) --> B(monolith) +``` + +Inevitably, some query plans become more complex while you're migrating types between subgraphs. By ranking your entities and moving the lowest-impact ones first, you can minimize this increase. + +## Implementation + +### 1. Make your monolith a real subgraph + +Now that you have a migration plan, you can start making schema and code changes. The first change is to add the [Apollo Federation subgraph specification](/federation/subgraph-spec/) to the monolith. The steps involved depend on which [Apollo-Federation-compatible library](/graphos/reference/federation/compatible-subgraphs) you use with your monolith's language and framework. + +The most important functionality to add is defining your entities (by adding `@key` directives) and adding their [reference resolvers](/graphos/schema-design/federated-schemas/entities/intro#defining-an-entity). + +### 2. Deploy your new subgraph + +Start with an empty subgraph to quickly set up your deployment and continuous integration pipelines. You can use this stub subgraph schema, which won't affect the client-facing schema: + +```graphql +extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@shareable", "@inaccessible"]) + +type Query { + _todo: String @shareable @inaccessible +} +``` + +After your new subgraph is deployed, set up [schema checks and publishes](/rover/commands/subgraphs#publishing-a-subgraph-schema-to-graphos) so that you can catch composition errors quickly and start contributing to the supergraph. + +### 3. Move an entity along with related types and relevant root fields + +1. Start by marking all the value types (enums and non-entity object types) you're going to move to the subgraph as `@shareable` in the monolith. +2. Copy the types and fields over to the subgraph schema and port their resolvers from the monolith. +3. Deploy the subgraph and test it by making calls to it directly. Use the [`_entities` root field](/federation/building-supergraphs/subgraphs-overview/#query_entities) to test joins between entities. + +When you're satisfied with the behavior and performance of your new subgraph, you can start moving all traffic to it and cleaning up the monolith. + +1. Use the [`@override`](/graphos/reference/federation/directives/#override) directive to mark fields in the subgraph with `@override(from: "monolith")`, telling the query planner to prefer the new subgraph over the monolith. +2. Remove types and fields from the monolith schema. +3. Delete unneeded resolvers from the monolith. +4. Remove `@override` directives from the subgraph. +5. Remove `@shareable` from types and fields in the subgraph when appropriate. + +### 4. Migrate additional functionality out of the monolith as desired + +Towards the end of the migration, you can decide whether to leave the monolith in place to handle the few entities that sit in the middle of your domain (such as `User`), or completely deconstruct the monolith into new services and decommission it. Either way, your newly federated GraphQL API is well-positioned to scale even larger in the future. diff --git a/docs/source/migrating-from-stitching.mdx b/docs/source/reference/migration/migrating-from-stitching.mdx similarity index 100% rename from docs/source/migrating-from-stitching.mdx rename to docs/source/reference/migration/migrating-from-stitching.mdx diff --git a/docs/source/federation-2/moving-to-federation-2.mdx b/docs/source/reference/migration/moving-to-federation-2.mdx similarity index 99% rename from docs/source/federation-2/moving-to-federation-2.mdx rename to docs/source/reference/migration/moving-to-federation-2.mdx index 42f0cc7ff..0875a417b 100644 --- a/docs/source/federation-2/moving-to-federation-2.mdx +++ b/docs/source/reference/migration/moving-to-federation-2.mdx @@ -88,13 +88,13 @@ Open the Settings page for the variant you want to move to Federation 2, then se Edit variant settings in Studio Click **Edit Configuration**. The following dialog appears: -Edit supported directives in Studio +Edit supported directives in Studio In the Federation Version dropdown, select **Federation 2** and click **Save**. diff --git a/docs/source/schema-design/federated-schemas/composition.mdx b/docs/source/schema-design/federated-schemas/composition.mdx new file mode 100644 index 000000000..112bd7614 --- /dev/null +++ b/docs/source/schema-design/federated-schemas/composition.mdx @@ -0,0 +1,104 @@ +--- +title: Schema Composition +subtitle: Learn how GraphOS combines subgraph schemas into a supergraph schema +description: Learn about schema composition in a federated GraphQL architecture. Explore strategies for handling conflicting types and directives. +redirectFrom: + - /federation/federated-types/composition + - /federation/federated-schemas/composition +--- + +In Apollo Federation, _composition_ is the process of combining a set of subgraph schemas into a supergraph schema: + +```mermaid +graph TB; + serviceA[Subgraph
schema
A]; + serviceB[Subgraph
schema
B]; + serviceC[Subgraph
schema
C]; + composition[["πŸ› 
Composition "]]; + supergraph{{"Supergraph schema
(A + B + C + routing machinery)"}}; + serviceA & serviceB & serviceC --> composition; + composition -- "(Composition succeeds)" --> supergraph; + class composition tertiary; +``` + +The supergraph schema includes all of the type and field definitions from your subgraph schemas. It also includes metadata that enables your router to intelligently route incoming GraphQL operations across all of your different subgraphs. + +## Supported methods + +You can perform schema composition with any of the following methods: + +### Automatically with GraphOS + +Apollo GraphOS performs composition automatically whenever you publish a subgraph schema. +This enables your running router to dynamically fetch an updated supergraph schema from Apollo as soon as it's available: + +```mermaid +graph LR; + subgraph "Your infrastructure" + serviceA[Products
subgraph]; + serviceB[Reviews
subgraph]; + gateway([Router]); + end + subgraph "GraphOS" + registry{{Schema Registry}}; + uplink{{Apollo
Uplink}} + end + serviceA & serviceB -->|Publishes schema| registry; + registry -->|Updates config| uplink; + gateway -->|Polls for config changes| uplink; + class registry secondary; + class uplink secondary; +``` + + + +GraphOS also provides a [schema linter](/graphos/platform/schema-management/linting) with [composition specific rules](/graphos/platform/schema-management/linting/rules#composition-rules) to help you follow best practices. You can set up schema checks for your graph in GraphOS Studio or perform one-off linting with the Rover CLI. Check out the [schema linting](/graphos/platform/schema-management/linting) docs to learn more. + + + +### Manually with the Rover CLI + +The [Rover CLI](https://www.apollographql.com/docs/rover/) supports a `supergraph compose` command that you can use to compose a supergraph schema from a collection of subgraph schemas: + +```bash showLineNumbers=false +rover supergraph compose --config ./supergraph-config.yaml +``` + +To learn how to install Rover and use this command, see the [Rover docs](/rover/). + +## Breaking composition + +Sometimes, your subgraph schemas might conflict in a way that causes composition to fail. This is called _breaking composition_. + +For example, take a look at these two subgraph schemas: + +

❌

+ + +```graphql {2} title="Subgraph A" +type Event @shareable { + timestamp: String! +} +``` + +```graphql {2} title="Subgraph B" +type Event @shareable { + timestamp: Int! +} +``` + + + +One subgraph defines `Event.timestamp` as a `String`, and the other defines it as an `Int`. Composition doesn't know which type to use, so it fails. + + + +For examples of valid inconsistencies in field return types, see [Differing shared field return types](/graphos/schema-design/federated-schemas/sharing-types/#return-types). + + + +Breaking composition is a helpful feature of federation! Whenever a team modifies their subgraph schema, those changes might conflict with another subgraph. But that conflict won't affect your router, because composition fails to generate a new supergraph schema. It's like a compiler error that prevents you from running invalid code. Refer to the [Composition Rules Reference](/graphos/reference/federation/composition-rules) for details. + +## Next steps + +Ready to compose your first supergraph? [Get started with GraphOS!](/graphos/get-started/guides/quickstart) diff --git a/docs/source/schema-design/federated-schemas/entities/best-practices.mdx b/docs/source/schema-design/federated-schemas/entities/best-practices.mdx new file mode 100644 index 000000000..e00b7a61c --- /dev/null +++ b/docs/source/schema-design/federated-schemas/entities/best-practices.mdx @@ -0,0 +1,84 @@ +--- +title: Thinking in Entities +subtitle: Best practices for designing your schema with entities +description: Schema design best practices for entities, including when to define, reference and extend entities. +published: 2023-01-09 +id: TN0026 +tags: [federation, schema-design] +redirectFrom: + - /technotes/TN0026-thinking-in-entities/ +--- + + + +If you're an enterprise customer looking for more material on this topic, try the [Enterprise best practices: Schema design](https://www.apollographql.com/tutorials/schema-design-best-practices) course on Odyssey. + +Not an enterprise customer? [Learn about GraphOS for Enterprise.](https://www.apollographql.com/pricing) + + + +Entities are the core building blocks of a federated graph, so the adoption of any schema design best practice must be approached with the unique role of entities in mind. While there's no requirement for subgraphs to define any entities at all with Apollo Federation, the federated schema design process often begins by thinking about what the initial entity types will be and how they will be referenced and extended throughout the graph to help preserve the separation of concerns between subgraphs both today and as the graph evolves in the future. + +## Define, reference, and extend entities as needed + +The [Apollo Federation specification](/graphos/reference/federation/subgraph-spec/) indicates that an Object or Interface type can be made into an entity by adding the `@key` directive to its definition in a subgraph schema. The `@key` directive defines a unique key for the entity and its `fields` argument will contain one or more of the type's fields. In the following example, the `Product` entity's primary key would be its `upc` field: + +```graphql title="Products Subgraph" +type Product @key(fields: "upc") { + upc: String! + name: String! + description: String +} +``` + +Setting the `upc` field as the key means that other subgraphs that want to use this entity will need to know at least that value for any product. The keys we define should be values that uniquely identify a resource. This is because we want to avoid scenarios where they are used to arbitrarily pass dynamic field data around query execution between subgraphs. + +After defining an entity in a schema, other subgraphs can reference that entity in their schemas. In order for the referencing subgraph's schema to be valid, it must define a stub of the entity in its schema. For example, we can reference a `Product` type defined in the products subgraph as the return type corresponding to a `product` field on a `Review` type defined in reviews subgraph: + +```graphql title="Reviews Subgraph" +type Review { + rating: Int + product: Product +} + +type Product @key(fields: "upc") { + upc: String! +} +``` + +The `@key` directive indicates that the reviews subgraph will be able to identify a product by its UPC value and therefore be able to connect to a product based on its `upc` primary key field, but the reviews subgraph does not need to be aware of any other details about a given product. + +Referencing entities is a key feature of federation, but it's only half of the story. While an entity will be owned by a single subgraph, other subgraphs might wish to add additional fields to the entity's type to provide a more holistic representation of the entity in the graph. Doing so is a simple as adding the additional field to the extended type in a non-originating subgraph. For example, a reviews subgraph's schema might add a `reviews` field to the extended `Product` type that was originally defined in the products subgraph: + +```graphql title="Reviews Subgraph" +type Review { + rating: Int + product: Product +} + +type Product @key(fields: "upc") { + upc: String! + reviews: [Review] +} +``` + +When extending entities, it's important to keep in mind that _the entity's originating subgraph will not be aware of the added fields_. Additionally, each field in an entity must only be defined once or the gateway will encounter schema composition errors. + +## Work from the entities outward + +When migrating from a client-only or monolithic GraphQL pattern, that work begins by identifying what entities will be exposed in the first subgraph extracted from the larger schema. When migrating from an architecture consisting of BFF-based GraphQL APIs or any other architecture of multiple overlapping graphs, the work of identifying entities (and determining new subgraph boundaries, in general) might be a bit more complex and involve some degree of negotiation with respect to type ownership, as well as a migration process to help account for any breaking changes that might result for clients. + +Whatever your architectural starting point, Apollo Federation was designed to allow the work of identifying entities and defining subgraph boundaries to be done in an incremental, non-disruptive fashion. Beginning to identify these entities is also the essential prerequisite for adopting the other schema design best practices that will follow. + +## `@defer` and entities + +Entities aren't just useful for connecting data across subgraphs. You can also use entities to enable the new [`@defer` directive for client-controlled prioritization of response data](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md). The GraphOS Router can [defer resolution of fields in entities](/graphos/routing/operations/defer) (and root fields) and handle sending data back to the client in prioritized chunks. By defining types as entities within your graph, clients can improve perceived user experience by adding a directive to their operations. + +## Next steps + +If you haven't already, follow the [Write Federated Schemas](/graphos/schema-design/federated-schemas/entities/intro) guide to learn how to define your first entity. + +To learn about more advanced ways of using entities, check out these guides: + +- [Define Advanced Keys](/graphos/schema-design/federated-schemas/entities/define-keys), including compound and nested key fields +- [Contribute and Reference Entity Fields](/graphos/schema-design/federated-schemas/entities/contribute-fields), including computed fields diff --git a/docs/source/entities/contribute-fields.mdx b/docs/source/schema-design/federated-schemas/entities/contribute-fields.mdx similarity index 100% rename from docs/source/entities/contribute-fields.mdx rename to docs/source/schema-design/federated-schemas/entities/contribute-fields.mdx diff --git a/docs/source/entities/define-advanced-keys.mdx b/docs/source/schema-design/federated-schemas/entities/define-advanced-keys.mdx similarity index 100% rename from docs/source/entities/define-advanced-keys.mdx rename to docs/source/schema-design/federated-schemas/entities/define-advanced-keys.mdx diff --git a/docs/source/schema-design/federated-schemas/entities/enforce-ownership.mdx b/docs/source/schema-design/federated-schemas/entities/enforce-ownership.mdx new file mode 100644 index 000000000..bcbb897df --- /dev/null +++ b/docs/source/schema-design/federated-schemas/entities/enforce-ownership.mdx @@ -0,0 +1,279 @@ +--- +title: Enforcing Entity Ownership in Apollo Federation +subtitle: Designating entity ownership in Apollo Federation 2 +description: Learn how to designate entity ownership and make "entity extension" a first-class concept in your Apollo Federation 2 supergraph. +published: 2023-02-16 +id: TN0036 +tags: [federation] +redirectFrom: + - /technotes/TN0036-owner-pattern/ +--- + +In Federation 2, the notion of "extending" an entity type is strictly conceptual. All definitions of a type in different subgraphs are merged according to the "shareability" of fields. In the following example, neither subgraph really owns or extends the `Product` entity. Instead, they both contribute fields to it. + + + +```graphql title="subgraph-a.graphql" +type Product @key(fields: "id") { + id: ID! + name: String +} +``` + +```graphql title="subgraph-b.graphql" +type Product @key(fields: "id") { + id: ID! + reviews: [Review] +} +``` + + + +Federation 1 required that one of these definitions used the `extend` keyword or `@extends` directive. Federation 2 drops this requirement to improve the flexibility of composition and reduce the possibility of hard composition errors. + +However, in some situations you still might want to designate an "owner" of an entity and make "entity extension" a first-class concept in your supergraph. + +One example is the ability assert which subgraph is responsible for documenting an entity. If two subgraphs add different descriptions to a type, composition selects one of those descriptions and emits a hint informing you of the inconsistency: + +``` +HINT: [INCONSISTENT_DESCRIPTION]: Element "Product" has inconsistent +descriptions across subgraphs. The supergraph will use description +(from subgraph "one"): + """ + The Product type. + """ +In subgraph "two", the description is: + """ + This is my description of the Product type. + """ +``` + + + +When a description is inconsistent across subgraphs, composition selects the description from the first subgraph alphabetically by name. + + + +A mechanism for deciding the "owner" of the type allows tools such as linters to catch these inconsistencies early in the development process. + +## Creating an `@owner` directive + +You can add an `@owner` directive to your supergraph using the [`@composeDirective`](/graphos/reference/federation/directives#composedirective) functionality introduced in Federation 2.2. + +```graphql title="subgraph-a.graphql" +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@composeDirective"]) + @link(url: "https://graphql.mycompany.dev/owner/v1.0", import: ["@owner"]) + @composeDirective(name: "@owner") + +directive @owner(team: String!) on OBJECT + +type Product @key(fields: "id") @owner(team: "subgraph-a") { + id: ID! + name: String +} +``` + +The `@owner` directive now appears in the supergraph. Because we did not define the directive as `repeatable`, subgraphs cannot define it with different arguments. + + + +```graphql title="supergraph.graphql" {69} +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION) + @link(url: "https://graphql.mycompany.dev/owner/v1.0", import: ["@owner"]) { + query: Query +} + +directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE + +directive @join__field( + graph: join__Graph + requires: join__FieldSet + provides: join__FieldSet + type: String + external: Boolean + override: String + usedOverridden: Boolean +) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION + +directive @join__graph(name: String!, url: String!) on ENUM_VALUE + +directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE + +directive @join__type( + graph: join__Graph! + key: join__FieldSet + extension: Boolean! = false + resolvable: Boolean! = true + isInterfaceObject: Boolean! = false +) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR + +directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION + +directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA + +directive @owner(team: String!) on OBJECT + +scalar join__FieldSet + +enum join__Graph { + ONE @join__graph(name: "one", url: "http://localhost:4001") +} + +scalar link__Import + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +type Product @join__type(graph: ONE, key: "id") @owner(team: "subgraph-a") { + id: ID! + name: String +} + +type Query @join__type(graph: ONE) { + products: [Product] +} +``` + + + +## Writing a lint rule using the `@owner` directive + +Here's an example of a [`@graphql-eslint`](https://the-guild.dev/graphql/eslint/docs) rule for subgraph schemas that uses the `@owner` directive to determine if a description is required: + + + +```js +const { getDirective } = require("@graphql-tools/utils"); +const { buildSchema } = require("graphql"); + +module.exports = { + rules: { + /** @type {import("@graphql-eslint/eslint-plugin").GraphQLESLintRule} */ + "subgraph-owned-type-has-description": { + create(context) { + const schema = buildSchema(context.getSourceCode().text, { + assumeValidSDL: true, // subgraph schemas may not be valid on their own + }); + + return { + /** + * For each object type defintion, look for an `@owner` directive. + * If it exist, require a description. + * If it doesn't, disallow a description. + */ + ObjectTypeDefinition(node) { + const type = schema.getType(node.name.value); + const owner = getDirective(schema, type, "owner"); + + if (owner && !node.description) { + context.report({ + node, + message: "Description is required on owned types", + }); + } + + if (!owner && node.description) { + context.report({ + node, + message: "Description not allowed on unowned types", + }); + } + }, + }; + }, + }, + }, +}; +``` + + + +## Using `@owner` to determine required approvers + +Another use case for the `@owner` directive is to determine required reviewers when a schema change affects a type owned by another team. + +The exact process depends on your source control and continuous integration systems. The following example steps assume you're using GitHub for both. + +1. Add a `pull_request` workflow: + + ```yaml title=".github/workflows/add-reviewers.yaml" + name: Add required reviewers for owned GraphQL types + on: [pull_request] + ``` + +2. Determine the affected types in the schema change: + + ```js + import { diff } from "@graphql-inspector/core"; + import { buildSchema } from "graphql"; + + const differences = diff( + buildSchema(schemaFromBaseRef, { assumeValidSDL: false }), + buildSchema(schemaFromCurrentRef, { assumeValidSDL: false }) + ); + + /* Derive a list of affected types from the result: + [ + { + "criticality": { + "level": "NON_BREAKING" + }, + "type": "FIELD_ADDED", + "message": "Field 'newField' was added to object type 'Product'", + "path": "Product.newField" + } + ] + */ + ``` + +3. Obtain the supergraph schema. + + You can use [`rover supergraph fetch`](https://www.apollographql.com/docs/rover/commands/supergraphs#supergraph-fetch) or retrieve it using the [Apollo Platform API](https://studio.apollographql.com/public/apollo-platform/explorer?explorerURLState=N4IgJg9gxgrgtgUwHYBcQC4QEcYIE4CeABAOIIoDKMADvgOZ4CG1AFgBQAkeCAZukQEkAIgEIAlEWAAdJESIA3RngCWjVG258iXXhOmy5RAPpGUBWkkaIZhogDoHRCLJJNWANSWrUkm7aIANowoCADOKACC1NR4EPIIYAAyjDBIUCy%2BBv5EAEYwygFgmdm23KEwASjFJbYmZhZWCH41cg52TrIAQvmFVFBQYaHVLYZQENwU6QhwjMMjo%2BMIQtDwyCjN8wC%2BGzXbWSV7uztEh4ane5sgm0A&variant=main). + +4. Extract the owners for the affected types: + + ```js + import { getDirective } from "@graphql-tools/utils"; + + const supergraphSchema = buildSchema(supergraphSdl); + const affectedTeams = []; + + for (const typeName of affectedTypes) { + const type = supergraphSchema.getType(typeName); + + const owner = getDirective(schema, type, "owner")?.[0]; + + if (owner) { + affectedTeams.push(owner.team); + } + } + ``` + +5. Add the team as reviewers on the pull request: + + ```js + import { Octokit } from "@octokit/action"; + + const octokit = new Octokit(); + + const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); + + await octokit.pulls.requestReviewers({ + owner, + repo, + pull_number: pullNumber, // ${{ github.event.number }} + team_reviewers: affectedTeams, + }); + ``` diff --git a/docs/source/entities/interfaces.mdx b/docs/source/schema-design/federated-schemas/entities/interfaces.mdx similarity index 100% rename from docs/source/entities/interfaces.mdx rename to docs/source/schema-design/federated-schemas/entities/interfaces.mdx diff --git a/docs/source/schema-design/federated-schemas/entities/intro.mdx b/docs/source/schema-design/federated-schemas/entities/intro.mdx new file mode 100644 index 000000000..ec12d03b5 --- /dev/null +++ b/docs/source/schema-design/federated-schemas/entities/intro.mdx @@ -0,0 +1,170 @@ +--- +title: Introduction to Entities +subtitle: Resolve federated types across multiple subgraphs +description: Learn to define, contribute to, and reference object types that resolve their fields across multiple subgraphs in a federated GraphQL architecture. +redirectFrom: + - /federation/entities +--- + +Federated schemas let multiple subgraphs collaboratively define and resolve fields for shared object types. +This guide shows you how to define a shared object type called an _entity_. + +Before you get started, you may want to check out the [Introduction to Apollo Federation](/graphos/schema-design/federated-schemas/federation) for a conceptual overview. + +## Entity overview + +_Entities_ are a fundamental aspect of federated schemas. +In a supergraph, an entity is an object type that can resolve its fields across multiple subgraphs. +Each subgraph can contribute different fields to the entity and is responsible for resolving only the fields that it contributes. +This enables subgraphs to adhere to the separation of concerns principle. + +For example, this `Product` entity's fields are defined and resolved across two subgraphs: + + + +```graphql title="Products subgraph" +type Product @key(fields: "upc") { + upc: ID! + name: String! + price: Int +} +``` + +```graphql title="Reviews subgraph" +type Product @key(fields: "productUpc") { + productUpc: ID! + rating: Int! +} +``` + + + + + +Only object types can be entities. + + + +This guide goes over how to define entities in your subgraph schemas and code. + +## Defining an entity + +To define an entity within a particular subgraph, you do the following: + +1. Apply the [`@key` directive](#1-define-a-key) to an object type. +2. Define the object type's [reference resolver](#2-define-a-reference-resolver). + + + + + + + +### 1. Define a `@key` + +In a subgraph schema, you can designate any object type as an entity by adding the `@key` directive to its definition, like so: + +```graphql {1} title="Products subgraph" +type Product @key(fields: "upc") { + upc: ID! + name: String! + price: Int +} +``` + +The `@key` directive defines an entity's _unique key_, which consists of one or more of the type's `fields`. +In the previous example, the `Product` entity's unique key is its `upc` field. +Every instance of an entity must be uniquely identifiable by its `@key` field(s). +Key fields' uniqueness enable your router to associate fields from different subgraphs with the same entity instance. + +In most cases, the `@key` field(s) for the same entity will be the same across subgraphs. +For example, if one subgraph uses `upc` as the `@key` field for the `Product` entity, other subgraphs should likely do the same. +However, this [isn't strictly required](/graphos/schema-design/federated-schemas/entities/define-keys/#differing-keys-across-subgraphs). + +If coming from a database context, it can be helpful to think of a `@key` as an entity's [primary key](https://en.wikipedia.org/wiki/Primary_key). +This term isn't completely accurate for entities since a single entity can have [multiple `@key`s](/graphos/schema-design/federated-schemas/entities/define-keys/#multiple-keys). The field(s) you select for an entity's `@key` must, however, uniquely identify the entity. +In that way, `@key`s are similar to [candidate keys](https://en.wikipedia.org/wiki/Candidate_key). + + + +```graphql title="Products subgraph" +type Product @key(fields: "upc") { + upc: ID! + name: String! + price: Int +} +``` + +```graphql title="Reviews subgraph" +type Product @key(fields: "productUpc") { + productUpc: ID! + inStock: Boolean! +} +``` + + + +For more information on advanced key options, like defining [multiple keys](/graphos/schema-design/federated-schemas/entities/define-keys/#multiple-keys) or [compound keys](/graphos/schema-design/federated-schemas/entities/define-keys/#compound-keys), see the guide on [Defining keys](/graphos/schema-design/federated-schemas/entities/define-keys). + +#### Key field limitations + +An entity's `@key` cannot include: + +- Fields that return a union or interface +- Fields that take arguments + +Though not strictly required, it's best to use non-nullable fields for keys. If you use fields that return `null` values, GraphOS may encounter issues resolving the entity. + +### 2. Define a reference resolver + +The `@key` directive effectively tells the router, "This subgraph can resolve an instance of this entity if you provide its unique key." For this to be true, the subgraph must define a _reference resolver_ for the entity. + + + +This section describes how to create reference resolvers in Apollo Server. +If you're using another [subgraph-compatible library](/graphos/reference/federation/compatible-subgraphs), see its documentation for creating reference resolvers or the equivalent functionality. + + + +For the `Product` entity defined [above](#1-define-a-key), the reference resolver might look like this: + +```js {4-6} title="resolvers.js" +// Products subgraph +const resolvers = { + Product: { + __resolveReference(productRepresentation) { + return fetchProductByID(productRepresentation.upc); + } + }, + // ...other resolvers... +} +``` + +Let's break this example down: + +- You declare an entity's reference resolver in your resolver map, as a member of the entity's corresponding object. +- A reference resolver's name is always `__resolveReference`. +- A reference resolver's first parameter is a representation of the entity being resolved. + - An entity representation is an object that contains the entity's `@key` fields, plus its `__typename` field. These values are automatically provided to your subgraph by your router. +- A reference resolver is responsible for returning all of the entity fields that this subgraph defines. + - In this example, the hypothetical `fetchProductByID` function fetches a particular `Product`'s field data based on its `upc`. + + + +A particular reference resolver might be called many times to resolve a single query. It's crucial that reference resolvers account for "N+1" issues (typically via [data loaders](https://github.com/graphql/dataloader)). For details, see [Handling the N+1 problem](/graphos/schema-design/guides/handling-n-plus-one). + + + +Every subgraph that contributes at least one unique field to an entity must define a reference resolver for that entity. + +To learn more about `__resolveReference` in Apollo Server, see the [API docs](/apollo-server/using-federation/api/apollo-subgraph/#__resolvereference). + +## Next steps + +Once you [add your subgraphs](/graphos/platform/graph-management/add-subgraphs) to your supergraph, GraphOS composes them into a supergraph schema. +Clients querying your supergraph can interact with entity fields without needing to know the details of which subgraphs contribute which fields. + +To learn about more advanced ways of using entities, check out these guides: + +- [Define Advanced Keys](/graphos/schema-design/federated-schemas/entities/define-keys), including compound and nested key fields +- [Contribute and Reference Entity Fields](/graphos/schema-design/federated-schemas/entities/contribute-fields), including computed fields diff --git a/docs/source/entities/migrate-fields.mdx b/docs/source/schema-design/federated-schemas/entities/migrate-fields.mdx similarity index 99% rename from docs/source/entities/migrate-fields.mdx rename to docs/source/schema-design/federated-schemas/entities/migrate-fields.mdx index 849be1547..8a0afa770 100644 --- a/docs/source/entities/migrate-fields.mdx +++ b/docs/source/schema-design/federated-schemas/entities/migrate-fields.mdx @@ -4,7 +4,7 @@ subtitle: Transfer entity fields from one subgraph to another description: Learn how to safely move parts of one subgraph to another subgraph in a federated GraphQL architecture using the @override directive. --- -import ProgressiveOverrideEnterprise from '../../shared/progressive-override-enterprise.mdx'; +import ProgressiveOverrideEnterprise from '../../../../shared/progressive-override-enterprise.mdx'; As your supergraph grows, you might want to move parts of one subgraph to another subgraph. For example, suppose your Payments subgraph defines a `Bill` entity: diff --git a/docs/source/entities/resolve-another-subgraphs-fields.mdx b/docs/source/schema-design/federated-schemas/entities/resolve-another-subgraphs-fields.mdx similarity index 100% rename from docs/source/entities/resolve-another-subgraphs-fields.mdx rename to docs/source/schema-design/federated-schemas/entities/resolve-another-subgraphs-fields.mdx diff --git a/docs/source/entities/use-contexts.mdx b/docs/source/schema-design/federated-schemas/entities/use-contexts.mdx similarity index 100% rename from docs/source/entities/use-contexts.mdx rename to docs/source/schema-design/federated-schemas/entities/use-contexts.mdx diff --git a/docs/source/schema-design/federated-schemas/federation.mdx b/docs/source/schema-design/federated-schemas/federation.mdx new file mode 100644 index 000000000..37896827f --- /dev/null +++ b/docs/source/schema-design/federated-schemas/federation.mdx @@ -0,0 +1,91 @@ +--- +title: Introduction to Apollo Federation +subtitle: Learn how federation combines your GraphQL APIs into a unified supergraph +description: Learn how Apollo Federation can help you declaratively combine your services into a unified, federated GraphQL API using a microservices architecture. +redirectFrom: + - /federation +--- + +Apollo Federation lets you declaratively combine multiple APIs into a single, federated graph. This federated graph enables clients to interact with your APIs through a single request. + +A client makes a request to the federated GraphQL API's single entry point called the _router_. The router intelligently orchestrates and distributes the request across your APIs and returns a unified response. For a client, the request and response cycle of querying the router looks the same as querying any GraphQL server. + + + + + + +Your federated GraphQL API, or _graph_, can be made of GraphQL APIs and other data sources. +[Learn how Apollo Connectors](../connectors/) simplify incorporating REST APIs into your graph. + + + + +To jump into building a federated GraphQL API, check out the [Apollo GraphOS Quickstart](/graphos/get-started/guides/quickstart). + + + + + + + +## Benefits of federation + +### Microservices architecture + +Apollo Federation lets API teams operate in a [microservices architecture](https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith) while exposing a unified GraphQL API to clients. Understanding these concepts can help you get the most out of federation. + +- Learn more about the [considerations and benefits of GraphQL](https://graphql.com/learn/what-is-graphql/). +- Learn more about the [considerations and benefits of microservices architecture](https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/). + +### Preserve client simplicity and performance + +A client may need to make multiple requests when interacting with multiple non-federated GraphQL APIs. This can happen when an organization adopting GraphQL has multiple teams developing APIs independently. Each team sets up a GraphQL API that provides the data used by that team. For example, a travel app may have separate GraphQL APIs for users, flights, and hotels: + + + + + +With a single federated graph, you preserve a powerful advantage of GraphQL over traditional REST APIs: the ability to fetch all the data you need in a single request. + + + + + +The router intelligently calls all the APIs it needs to complete requests rather than simply forwarding them. +For performance and security reasons, clients should only query the router, and only the router should query the constituent APIs. +No client-side configuration is required. + +### Design schemas at scale + +Some alternative approaches to combining GraphQL APIs impose limits on your schema, like adding namespaces or representing relationships with IDs instead of types. With these approaches, your individual GraphQL API schemas may look unchangedβ€”but the resulting federated schema that clients interact with is more complex. Subsequently, it requires you to make frontend as well as backend changes. + +With Apollo Federation, clients can interact with the federated schema as if it were a monolith. Consumers of your API shouldn't know or care that it's implemented as microservices. + +### Maintain a single API + +With federation, every team contributes directly to the overall federated GraphQL schema. Each team can work independently without needing to maintain multiple API layers. This frees your platform team to focus on the quality of your API rather than keeping it up to date. + +## Next steps + +Before continuing, it's helpful to know some terminology: + +- When combining multiple GraphQL APIs, the single, federated graph is called a _supergraph_. +- In a supergraph, the constituent APIs are called _subgraphs_. + + + + +Different subgraphs in the same supergraph can use different server implementations and even different programming languages as long as they are [federation-compatible](../../reference/federation/compatible-subgraphs). + +Ready to get started? + +- Create and run a federated graph with the [Quickstart](/graphos/get-started/guides/quickstart). + +- Connect REST APIs to your graph using Apollo Connectors with the [REST quickstart](/graphos/get-started/guides/rest-quickstart). + +### Additional resources + +Depending on your goals, you have several options for learning more about federation: +- If you're new to federated architecture, this [overview article](https://graphql.com/learn/federated-architecture/) can familiarize the concepts. +- If you learn best by doing, this [interactive course](https://www.apollographql.com/tutorials/voyage-part1) teaches you to build an example supergraph using Apollo Federation. diff --git a/docs/source/schema-design/federated-schemas/schema-types.mdx b/docs/source/schema-design/federated-schemas/schema-types.mdx new file mode 100644 index 000000000..6ccb51db1 --- /dev/null +++ b/docs/source/schema-design/federated-schemas/schema-types.mdx @@ -0,0 +1,235 @@ +--- +title: Federated Schemas +subtitle: Learn about the different types of GraphQL schemas +description: Learn about subgraph, supergraph, and API schemas in federated GraphQL architectures. +redirectFrom: + - /federation/federated-schemas/ + - /federation/federated-types/ +--- + +A federated supergraph uses multiple "types" of GraphQL schemas: + +```mermaid +graph TB; + serviceA[Subgraph
schema
A]; + serviceB[Subgraph
schema
B]; + serviceC[Subgraph
schema
C]; + composition[["πŸ› 
Composition "]]; + supergraph{{"Supergraph schema
(A + B + C + routing machinery)"}}; + api(["API schema
(A + B + C)"]); + serviceA & serviceB & serviceC --> composition; + composition -- "(Composition succeeds)" --> supergraph; + supergraph -- "(Remove routing machinery)" --> api; + class composition tertiary; +``` + +* **Subgraph schemas.** Each subgraph has a distinct schema that indicates which types and fields of your composed supergraph it can resolve. + * These are the only schemas that your teams define manually. +* **Supergraph schema.** This schema combines all of the types and fields from your subgraph schemas, plus some federation-specific information that tells your router which subgraphs can resolve which fields. + * This schema is the result of performing [composition](/graphos/schema-design/federated-schemas/composition/) on your collection of subgraph schemas. +* **API schema.** This schema is similar to the supergraph schema, but it omits federation-specific types, fields, and directives that are considered "machinery" and are not part of your public API. + * This is the schema that your router exposes to clients, which don't need to know internal implementation details about your graph. + +Let's look at an example! + +## Subgraph schemas + +Below are example schemas for three subgraphs in an e-commerce company's supergraph. Each subgraph is implemented as a separate GraphQL API: + + + +```graphql title="Users" +type Query { + me: User +} + +type User @key(fields: "id") { + id: ID! + username: String! @shareable +} + +# (Subgraph schemas include +# this to opt in to +# Federation 2 features.) +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", + import: ["@key", "@shareable"]) +``` + +```graphql title="Products" +type Query { + topProducts(first: Int = 5): [Product] +} + +type Product @key(fields: "upc") { + upc: String! + name: String! + price: Int +} + +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", + import: ["@key", "@shareable"]) +``` + + + + + +```graphql title="Reviews" +type Review { + body: String + author: User @provides(fields: "username") + product: Product +} + +type User @key(fields: "id") { + id: ID! + username: String! @external + reviews: [Review] +} + +type Product @key(fields: "upc") { + upc: String! + reviews: [Review] +} + +# (This subgraph uses additional +# federated directives) +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", + import: ["@key", "@shareable", "@provides", "@external"]) +``` + + + +As these schemas show, multiple subgraphs can contribute unique fields to a single type. For example, the Products subgraph and the Reviews subgraph both contribute fields to the `Product` type. + +## Supergraph schema + +The supergraph schema is the output of [schema composition](/graphos/schema-design/federated-schemas/composition/). It serves the following purposes: + +* It provides your router with the name and endpoint URL for each of your subgraphs. +* It includes all types and fields defined by all of your subgraphs. +* It tells your router which of your subgraphs can resolve which GraphQL fields. + +Here's the supergraph schema composed with [the subgraph schemas above](#subgraph-schemas): + + + +```graphql +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION) +{ + query: Query +} + +directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE + +directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean, override: String, usedOverridden: Boolean) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION + +directive @join__graph(name: String!, url: String!) on ENUM_VALUE + +directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE + +directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true, isInterfaceObject: Boolean! = false) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR + +directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION + +directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA + +scalar join__FieldSet + +enum join__Graph { + PRODUCTS @join__graph(name: "products", url: "http://localhost:4002/graphql") + REVIEWS @join__graph(name: "reviews", url: "http://localhost:4003/graphql") + USERS @join__graph(name: "users", url: "http://localhost:4001/graphql") +} + +scalar link__Import + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +type Product + @join__type(graph: PRODUCTS, key: "upc") + @join__type(graph: REVIEWS, key: "upc") +{ + upc: String! + name: String! @join__field(graph: PRODUCTS) + price: Int @join__field(graph: PRODUCTS) + reviews: [Review] @join__field(graph: REVIEWS) +} + +type Query + @join__type(graph: PRODUCTS) + @join__type(graph: REVIEWS) + @join__type(graph: USERS) +{ + topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCTS) + me: User @join__field(graph: USERS) +} + +type Review + @join__type(graph: REVIEWS) +{ + body: String + author: User @join__field(graph: REVIEWS, provides: "username") + product: Product +} + +type User + @join__type(graph: REVIEWS, key: "id") + @join__type(graph: USERS, key: "id") +{ + id: ID! + username: String! @join__field(graph: REVIEWS, external: true) @join__field(graph: USERS) + reviews: [Review] @join__field(graph: REVIEWS) +} +``` + + + +As you can see, the supergraph schema includes a lot of Federation-specific additions! These additions are used only by the router, and you'll never need to add them manually. + +## API schema + +The router uses its [supergraph schema](#supergraph-schema) to produce an **API schema**, which it exposes to clients as your actual GraphQL API. This schema cleanly and logically represents the combination of your [subgraph schemas](#subgraph-schemas): + +```graphql +type Product { + name: String! + price: Int + reviews: [Review] + upc: String! +} + +type Query { + me: User + topProducts(first: Int = 5): [Product] +} + +type Review { + author: User + body: String + product: Product +} + +type User { + id: ID! + reviews: [Review] + username: String! +} +``` + +Unlike the supergraph schema, this schema hides the fact that your GraphQL API is composed of multiple distinct GraphQL APIs. diff --git a/docs/source/schema-design/federated-schemas/sharing-types.mdx b/docs/source/schema-design/federated-schemas/sharing-types.mdx new file mode 100644 index 000000000..3a886fe35 --- /dev/null +++ b/docs/source/schema-design/federated-schemas/sharing-types.mdx @@ -0,0 +1,637 @@ +--- +title: Value Types in Apollo Federation +subtitle: Share types and fields across multiple subgraphs +description: Learn how to share GraphQL types and fields across subgraphs with Apollo Federation. +redirectFrom: + - /federation/federated-types/sharing-types + - /federation/federated-schemas/sharing-types +--- + +In a federated graph, it's common to want to reuse a GraphQL type across multiple subgraphs. + +For example, suppose you want to define and reuse a generic `Position` type in different subgraphs: + +```graphql +type Position { + x: Int! + y: Int! +} +``` + +Types like this are called _value types_. This article describes how to share value types and their fields in federated graph, enabling multiple subgraphs to define and resolve them. + +## Sharing object types + +By default, in Federation 2 subgraphs, a single object field can't be defined or resolved by more than one subgraph schema. + +Consider the following `Position` example: + +

❌

+ + + +```graphql {2-3} title="Subgraph A" +type Position { + x: Int! + y: Int! +} +``` + +```graphql {2-3} title="Subgraph B" +type Position { + x: Int! + y: Int! +} +``` + + + +Attempting to compose these two subgraph schemas together will [break composition](/graphos/schema-design/federated-schemas/composition/#breaking-composition). The router doesn't know which subgraph is responsible for resolving `Position.x` and `Position.y`. To enable multiple subgraphs to resolve these fields, you must first mark that field as [`@shareable`](#using-shareable). + + + +As an alternative, if you want Subgraphs A and B to resolve different fields of `Position`, you can designate the `Position` type as an [entity](/graphos/schema-design/federated-schemas/entities/intro). + + + +### Using `@shareable` + +The `@shareable` directive enables multiple subgraphs to resolve a particular object field (or set of object fields). + +To use `@shareable` in a subgraph schema, you first need to add the following snippet to that schema to [opt in to Federation 2](/graphos/reference/migration/to-federation-version-2/#opt-in-to-federation-2): + +```graphql +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", + import: ["@key", "@shareable"]) +``` + +Then you can apply the `@shareable` directive to an object type, or to individual fields of that type: + +

βœ…

+ + + +```graphql {1} title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! +} +``` + +```graphql {2-3} title="Subgraph B" +type Position { + x: Int! @shareable + y: Int! @shareable +} +``` + + + + +Marking a type as `@shareable` is equivalent to marking all of its fields as `@shareable`, so the two subgraph definitions above are equivalent. + + + +Both subgraphs A and B can now resolve the `x` and `y` fields for the `Position` type, and our subgraph schemas will successfully compose into a supergraph schema. + +#### ⚠️ Important considerations for `@shareable` + +* If a type or field is marked `@shareable` in any subgraph, it must be marked either `@shareable` or [`@external`](/graphos/reference/federation/directives/#external) in every subgraph that defines it. Otherwise, composition fails. +* If multiple subgraphs can resolve a field, make sure each subgraph's resolver for that field behaves identically. Otherwise, queries might return inconsistent results depending on which subgraph resolves the field. + +#### Using `@shareable` with `extend` + +If you apply `@shareable` to an object type declaration, it only applies to the fields within that exact declaration. It does not apply to other declarations for that same type: + +```graphql title="Subgraph A" +type Position @shareable { + x: Int! # shareable + y: Int! # shareable +} + +extend type Position { + # highlight-start + z: Int! # ⚠️ NOT shareable! + # highlight-end +} +``` + +Using the `extend` keyword, the schema above includes two different declarations for `Position`. Because only the first declaration is marked `@shareable`, `Position.z` is not considered shareable. + +To make `Position.z` shareable, you can do one of the following: + +- Mark the individual field `z` with `@shareable`. + + ```graphql + extend type Position { + # highlight-start + z: Int! @shareable + # highlight-end + } + ``` + +- Mark the entire `extend` declaration with `@shareable`. + + - This strategy requires targeting v2.2 or later of the Apollo Federation specification in your subgraph schema. Earlier versions do not support applying `@shareable` to the same object type multiple times. + + ```graphql + extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@shareable"]) #highlight-line + + extend type Position @shareable { #highlight-line + z: Int! + } + ``` + +## Differing shared fields + +Shared fields can only differ in their [return types](#return-types) and [arguments](#arguments) in specific ways. +If fields you want to share between subgraphs differ more than is permitted, use [entities](/graphos/schema-design/federated-schemas/entities/intro) instead of shareable value types. + + +### Return types + +Let's say two subgraphs both define an `Event` object type with a `timestamp` field: + +

❌

+ + + +```graphql {2} title="Subgraph A" +type Event @shareable { + timestamp: Int! +} +``` + +```graphql {2} title="Subgraph B" +type Event @shareable { + timestamp: String! +} +``` + + + +Subgraph A's `timestamp` returns an `Int`, and Subgraph B's returns a `String`. This is invalid. When composition attempts to generate an `Event` type for the supergraph schema, it fails due to an unresolvable conflict between the two `timestamp` field definitions. + +Next, look at these varying definitions for the `Position` object type: + +

βœ…

+ + + +```graphql {2-3} title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! +} +``` + +```graphql {2-3} title="Subgraph B" +type Position @shareable { + x: Int + y: Int +} +``` + + + +The `x` and `y` fields are non-nullable in Subgraph A, but they're nullable in Subgraph B. This is valid. Composition recognizes that it can use the following definition for `Position` in the supergraph schema: + + +```graphql title="Supergraph schema" +type Position { + x: Int + y: Int +} +``` + +This definition works for querying Subgraph A, because Subgraph A's definition is more restrictive than this (a non-nullable value is always valid for a nullable field). In this case, composition coerces Subgraph A's `Position` fields to satisfy the reduced restrictiveness of Subgraph B. + + + +Subgraph A's actual subgraph schema is not modified. Within Subgraph A, `x` and `y` remain non-nullable. + + + +### Arguments + +Arguments for a shared field can differ between subgraphs in certain ways: + +* If an argument is required in at least one subgraph, it can be optional in other subgraphs. It cannot be omitted. +* If an argument is optional in every subgraph where it's defined, it is technically valid to omit it in other subgraphs. However: + * ⚠️ If a field argument is omitted from any subgraph, that argument is omitted from the supergraph schema entirely. This means that clients can't provide the argument for that field. + +

βœ…

+ + + +```graphql {3} title="Subgraph A" +type Building @shareable { + # Argument is required + height(units: String!): Int! +} +``` + +```graphql {3} title="Subgraph B" +type Building @shareable { + # Argument can be optional + height(units: String): Int! +} +``` + + + +

❌

+ + + +```graphql {3} title="Subgraph A" +type Building @shareable { + # Argument is required + height(units: String!): Int! +} +``` + +```graphql {3} title="Subgraph B" +type Building @shareable { + # ⚠️ Argument can't be omitted! ⚠️ + height: Int! +} +``` + + + +

⚠️

+ + + +```graphql {3} title="Subgraph A" +type Building @shareable { + # Argument is optional + height(units: String): Int! +} +``` + +```graphql {5} title="Subgraph B" +type Building @shareable { + # Argument can be omitted, BUT + # it doesn't appear in the + # supergraph schema! + height: Int! +} +``` + + + +For more information, see [Input types and field arguments](/graphos/schema-design/federated-schemas/composition#input-types-and-field-arguments). + +### Omitting fields + +Look at these two definitions of a `Position` object type: + +

⚠️

+ + + +```graphql title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! +} +``` + +```graphql title="Subgraph B" +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + + + +Subgraph B defines a `z` field, but Subgraph A doesn't. In this case, when composition generates the `Position` type for the supergraph schema, it includes all three fields: + + + +```graphql title="Supergraph schema" +type Position { + x: Int! + y: Int! + z: Int! +} +``` + + + +This definition works for Subgraph B, but it presents a problem for Subgraph A. Let's say Subgraph A defines the following `Query` type: + + + +```graphql title="Subgraph A" +type Query { + currentPosition: Position! +} +``` + + + +According to the hypothetical supergraph schema, the following query is valid against the supergraph: + +

❌

+ + + +```graphql +query GetCurrentPosition { + currentPosition { + x + y + z # ⚠️ Unresolvable! ⚠️ + } +} +``` + + + +And here's the problem: if Subgraph B doesn't define `Query.currentPosition`, this query must be executed on Subgraph A. But Subgraph A is missing the `Position.z` field, so that field is unresolvable! + +Composition recognizes this potential problem, and it fails with an error. To learn how to fix it, check out [Solutions for unresolvable fields](/graphos/reference/federation/composition-rules#solutions-for-unresolvable-fields). + +## Adding new shared fields + +Adding a new field to a value type can cause composition issues, because it's challenging to add the field to all defining subgraphs at the same time. + +Let's say we're adding a `z` field to our `Position` value type, and we start with Subgraph A: + +

⚠️

+ + + +```graphql {4} title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + +```graphql title="Subgraph B" +type Position @shareable { + x: Int! + y: Int! +} +``` + + + +It's likely that when we attempt to compose these two schemas, composition will fail, because Subgraph B can't resolve `Position.z`. + +To incrementally add the field to all of our subgraphs without breaking composition, we can use the [`@inaccessible` directive](#using-inaccessible). + + +### Using `@inaccessible` + +If you apply the `@inaccessible` directive to a field, composition omits that field from your router's API schema. This helps you incrementally add a field to multiple subgraphs without breaking composition. + +To use `@inaccessible` in a subgraph, first make sure you include it in the `import` array of your Federation 2 opt-in declaration: + +```graphql {3} title="Subgraph A" +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", + import: ["@key", "@shareable", "@inaccessible"]) +``` + +Then, whenever you add a new field to a value type, apply `@inaccessible` to that field if it isn't yet present in every subgraph that defines the value type: + + + +```graphql {4} title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! + z: Int! @inaccessible +} +``` + +```graphql title="Subgraph B" +type Position @shareable { + x: Int! + y: Int! +} +``` + + + +Even if `Position.z` is defined in multiple subgraphs, you only need to apply `@inaccessible` in one subgraph to omit it. In fact, you might want to apply it in only one subgraph to simplify removing it later. + +With the syntax above, composition omits `Position.z` from the generated API schema, and the resulting `Position` type includes only `x` and `y` fields. + + + +Notice that `Position.z` does appear in the supergraph schema, but the API schema enforces which fields clients can include in operations. [Learn more about federated schemas.](/graphos/schema-design/federated-schemas/schema-types) + + + +Whenever you're ready, you can now add `Position.z` to Subgraph B: + + + +```graphql title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! + z: Int! @inaccessible +} +``` + +```graphql {4} title="Subgraph B" +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + + + +At this point, `Position.z` is still `@inaccessible`, so composition continues to ignore it. + +Finally, when you've added `Position.z` to every subgraph that defines `Position`, you can remove `@inaccessible` from Subgraph A: + + + +```graphql {4} title="Subgraph A" +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + +```graphql title="Subgraph B" +type Position @shareable { + x: Int! + y: Int! + z: Int! +} +``` + + + +Composition now successfully includes `Position.z` in the supergraph schema! + +## Unions and interfaces + +In Federation 2, `union` and `interface` type definitions can be shared between subgraphs by default, and those definitions can differ: + + +```graphql {1, 3, 9} title="Subgraph A" +union Media = Book | Movie + +interface User { + name: String! +} +``` + +```graphql {1, 3, 9} title="Subgraph B" +union Media = Book | Podcast + +interface User { + name: String! + age: Int! +} +``` + + + +[Compositional logic](/graphos/schema-design/federated-schemas/composition#merging-types-from-multiple-subgraphs) merges these definitions in your supergraph schema: + +```graphql title="Supergraph schema" +union Media = Book | Movie | Podcast + +# The object types that implement this interface are +# responsible for resolving these fields. +interface User { + name: String! + age: Int! +} +``` + +This can be useful when different subgraphs are responsible for different subsets of a particular set of related types or values. + + + +You can also use the `enum` type across multiple subgraphs. For details, see [Merging types from multiple subgraphs](composition#enums). + + + +### Challenges with shared interfaces + +Sharing an interface type across subgraphs introduces maintenance challenges whenever that interface changes. Consider these subgraphs: + + + +```graphql title="Subgraph A" +interface Media { + id: ID! + title: String! +} + +type Book implements Media { + id: ID! + title: String! +} +``` + +```graphql title="Subgraph B" +interface Media { + id: ID! + title: String! +} + +type Podcast implements Media { + id: ID! + title: String! +} +``` + + + +Now, let's say Subgraph B adds a `creator` field to the `Media` interface: + +

❌

+ + + +```graphql title="Subgraph A" +interface Media { + id: ID! + title: String! +} + +type Book implements Media { + id: ID! + title: String! + # ❌ Doesn't define creator! +} +``` + +```graphql title="Subgraph B" +interface Media { + id: ID! + title: String! + creator: String! #highlight-line +} + +type Podcast implements Media { + id: ID! + title: String! + creator: String! #highlight-line +} +``` + + + +This breaks composition, because `Book` also implements `Media` but doesn't define the new `creator` field. + +To prevent this error, all implementing types across all subgraphs need to be updated to include all fields of `Media`. This becomes more and more challenging to do as your number of subgraphs and teams grows. Fortunately, there's a [solution](#solution-entity-interfaces). + +#### Solution: Entity interfaces + +Apollo Federation 2.3 introduces a powerful abstraction mechanism for interfaces, enabling you to add interface fields across subgraphs without needing to update every single implementing type. + +[Learn more about entity interfaces.](/graphos/schema-design/federated-schemas/entities/interfaces/) + +## Input types + +Subgraphs can share `input` type definitions, but composition merges their fields using an intersection strategy. When `input` types are composed across multiple subgraphs, only mutual fields are preserved in the supergraph schema: + + + +```graphql title="Subgraph A" +input UserInput { + name: String! + age: Int # Not in Subgraph B +} +``` + +```graphql title="Subgraph B" +input UserInput { + name: String! + email: String # Not in Subgraph A +} +``` + + + +Compositional logic merges only the fields that all `input` types have in common. To learn more, see [Merging input types and field arguments](/graphos/schema-design/federated-schemas/composition#input-types-and-field-arguments). + +```graphql title="Supergraph schema" +input UserInput { + name: String! +} +``` + +To learn more about how composition merges different schema types under the hood, see [Merging types during composition](/graphos/schema-design/federated-schemas/composition#merging-types-from-multiple-subgraphs).