Por que Federation existe
Um schema monolítico com 800 tipos owned por 20 times vira inferno de merge. Federation fatia o grafo em subgraphs, cada um owned por um time, compostos por um router em runtime. Contrato explícito: @key marca entities, @external/@requires/@provides coordenam extensões cross-subgraph.
Subgraph Users
extend schema @link(
url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@shareable"]
)
type User @key(fields: "id") {
id: ID!
name: String!
email: String
}
type Query {
me: User
user(id: ID!): User
}Subgraph Reviews estendendo User
extend schema @link(
url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@external"]
)
type Review {
id: ID!
body: String!
author: User!
}
type User @key(fields: "id") {
id: ID! @external
reviews: [Review!]!
}O subgraph Reviews não é dono de User, apenas estende. O router resolve user.reviews chamando _entities no Reviews com a representation id. Users subgraph nem sabe que Reviews existe.
Router + schema check em CI
# Publicar subgraph
rover subgraph publish my-graph@prod \
--name users \
--schema ./users.graphql \
--routing-url https://users.internal/graphql
# Schema check em PR (bloqueia breaking)
rover subgraph check my-graph@prod \
--name users \
--schema ./users.graphqlApollo Router (Rust) substituiu Apollo Gateway (Node). Mais rápido, query planner melhor, suporta plugins via Rhai/Wasm. GraphOS ou Hive gerenciam o schema registry; em on-prem dá para rodar o router standalone apontando para supergraph.graphql estático.
Armadilhas
Federation não elimina N+1 cross-subgraph — o router faz entity fetch batching, mas queries com muitos hops saltam entre subgraphs. @requires que puxa campos de outro subgraph vira lookup extra. Autorização deve viver no subgraph dono, nunca no router (router não conhece regras de negócio).
Não adote Federation para fatiar monolito prematuro. Sem times distintos, você só ganhou complexidade. O problema que Federation resolve é organizacional; a solução é técnica.