Knowledge

GraphQL Federation: arquitetando microsserviços sem o problema N+1

Como Apollo Federation permite deploys autônomos de microsserviços enquanto mantém uma superfície de API GraphQL unificada.

09/03/20268 min de leituraKnowledge
GraphQL Federation: arquitetando microsserviços sem o problema N+1

Resumo executivo

Como Apollo Federation permite deploys autônomos de microsserviços enquanto mantém uma superfície de API GraphQL unificada.

Ultima atualizacao: 09/03/2026

O problema de coordenação de API de microsserviços

Organizações modernas enfrentam um paradoxo: querem a autonomia de microsserviços — onde times podem fazer deploy independentemente sem coordenar com outros times — mas também precisam de uma superfície de API unificada para seus clientes frontend.

A abordagem REST tradicional força uma escolha entre:

  1. Orquestração de API Gateway: O gateway chama múltiplos serviços e compõe respostas. Isso cria acoplamento apertado — qualquer mudança em um serviço downstream quebra a lógica de composição do gateway.
  1. Agregação frontend: Times frontend chamam múltiplos serviços diretamente. Isso cria complexidade exponencial — cada time frontend deve entender e gerenciar fronteiras de serviço, transformação de dados e tratamento de erros.
  1. Padrão BFF (Backend for Frontend): Serviços BFF dedicados por frontend. Isso duplica lógica entre times e cria gargalos de coordenação quando múltiplos frontends precisam dos mesmos dados.

GraphQL Federation resolve isso permitindo que cada microsserviço defina seu próprio schema GraphQL enquanto apresenta um schema federado unificado aos clientes. Times fazem deploy autonomamente, mas desenvolvedores frontend veem uma única API coerente.

Como Federation funciona: a arquitetura de subgrafos

Em Federation, sua API GraphQL é composta de múltiplos subgrafos — cada um propriedade e deploy de um time diferente. Um Gateway fica na frente desses subgrafos, apresentando um schema unificado aos clientes e roteando queries apropriadamente.

                    ┌─────────────────┐
                    │   Frontend      │
                    │   Aplicações    │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │   Gateway       │
                    │   (Apollo)      │
                    └────────┬────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
    ┌────▼────┐        ┌────▼────┐        ┌────▼────┐
    │Products │        │ Orders  │        │ Reviews │
    │Subgrafo │        │Subgrafo │        │Subgrafo │
    └─────────┘        └─────────┘        └─────────┘

Cada subgrafo expõe um servidor GraphQL padrão usando Apollo Server, GraphQL Yoga ou outra implementação compatível. O Gateway descobre subgrafos através de um arquivo de configuração ou um serviço de registro, busca seus schemas e os compõe em um schema federado.

Definindo entidades: a cola entre subgrafos

Entidades são a abstração central que conecta subgrafos. Uma entidade é um tipo que pode ser estendido por múltiplos subgrafos usando a diretiva @key:

graphql# subgrafo products
type Product @key(fields: "id") {
  id: ID!
  name: String!
  price: Float!
  description: String
}

extend type Query {
  product(id: ID!): Product
}

A diretiva @key(fields: "id") informa à Federation que Product é uma entidade unicamente identificada pelo campo id. Outros subgrafos agora podem estender este tipo:

graphql# subgrafo reviews
type Product @key(fields: "id") {
  id: ID!
  reviews: [Review!]!
  averageRating: Float!
}

type Review {
  id: ID!
  productId: ID!
  author: String!
  rating: Int!
  content: String!
}

Quando o Gateway recebe uma query como:

graphqlquery {
  product(id: "p123") {
    name
    reviews {
      author
      rating
    }
  }
}

Ele divide isso em duas requisições:

  1. product(id: "p123") { name } → Subgrafo Products
  2. _entities(representations: [{ __typename: "Product", id: "p123" }]) → Subgrafo Reviews

O subgrafo Reviews recebe a representação da entidade e a usa para buscar reviews para aquele ID de produto.

Padrões avançados de entidades

Chaves compostas

Entidades podem ser identificadas por múltiplos campos:

graphqltype Order @key(fields: "userId orderId") {
  userId: ID!
  orderId: ID!
  status: OrderStatus!
  total: Float!
}

Isso é útil quando entidades não têm um identificador natural de campo único ou ao combinar chaves lógicas.

Múltiplas chaves

Entidades podem ter múltiplas diretivas key para diferentes padrões de acesso:

graphqltype User @key(fields: "id") @key(fields: "email") {
  id: ID!
  email: String!
  name: String!
}

O Gateway usará a chave apropriada baseado em como a entidade é referenciada na query.

Compartilhamento de campos com @provides e @requires

Ao estender uma entidade, você pode querer adicionar campos que o subgrafo original não conhece, ou referenciar campos que só existem no subgrafo que está estendendo:

graphql# subgrafo products define um produto
type Product @key(fields: "id") {
  id: ID!
  name: String!
  price: Float!
  inventory: Int!
}

O subgrafo inventory pode estender este tipo e fornecer campos adicionais:

graphql# subgrafo inventory
type Product @key(fields: "id") @extends {
  id: ID!
  inStock: Boolean! @external
  warehouseLocation: String!
}

Mas e se inStock for computacionalmente caro de calcular? O subgrafo inventory pode calculá-lo uma vez e fornecê-lo para outros subgrafos:

graphqltype Product @key(fields: "id") @extends {
  id: ID!
  inStock: Boolean! @external @provides(fields: "warehouseLocation")
  warehouseLocation: String!
}

Por outro lado, se o subgrafo inventory precisa de dados do subgrafo products para calcular seus campos:

graphqltype Product @key(fields: "id") @extends {
  id: ID!
  price: Float! @external @requires(fields: "price")
  inStock: Boolean!
  priceEligibleForDiscount: Boolean!
}

Resolvendo o problema N+1 no Gateway

O problema clássico N+1 do GraphQL — onde resolver uma lista de entidades dispara N+1 queries de banco de dados — torna-se exponencialmente pior em arquiteturas distribuídas. O Gateway resolve isso através de planejamento de query e batching.

Planejamento de query

Quando uma query chega, o Gateway analisa e cria um plano de execução. Ele identifica quais subgrafos estão envolvidos e quais queries precisam ser enviadas para cada um. Criticamente, ele pode fazer batch de requisições de entidade:

graphqlquery {
  products {
    id
    name
    reviews {
      rating
    }
  }
}

Sem Federation, isso pode disparar N+1 queries. Com Federation, o Gateway:

  1. Chama o subgrafo products: products { id name } → Retorna 10 produtos
  2. Chama o subgrafo reviews uma vez: _entities([{ id: p1 }, { id: p2 }, ... { id: p10 }]) { reviews { rating } }

O subgrafo reviews recebe todos os 10 IDs de produto em uma única requisição e pode buscar eficientemente todos os reviews em batch.

Padrão DataLoader em subgrafos

Para performance ótima, subgrafos devem implementar DataLoader ou padrões similares de batching:

typescriptimport DataLoader from 'dataloader';

const reviewsLoader = new DataLoader(async (productIds: string[]) => {
  const reviews = await db.reviews.where('productId').in(productIds).toArray();
  return productIds.map(id => reviews.filter(r => r.productId === id));
});

const resolvers = {
  Product: {
    reviews: (product) => reviewsLoader.load(product.id),
  },
};

Isso garante que mesmo quando o Gateway faz batch eficiente de requisições, o subgrafo não faz chamadas de banco de dados redundantes.

Estratégias de deploy em produção

Padrões de deploy do Gateway

Existem três padrões principais para deploy do Apollo Gateway:

  1. Apollo Router gerenciado: A opção mais fácil. Apollo hospeda seu Gateway, cuida da infraestrutura e fornece observabilidade. Melhor para times que querem minimizar overhead operacional.
  1. Apollo Router self-hosted: Você faz deploy do Apollo Router como container em sua própria infraestrutura (Kubernetes, ECS, etc.). Dá controle sobre configuração e custos.
  1. Gateway customizado com Apollo Server: Para máxima flexibilidade, construa um Gateway customizado usando Apollo Server. Permite middleware customizado, lógica de autenticação e estratégias de cache.

Independência de deploy de subgrafos

Uma vantagem chave de Federation é que subgrafos podem ser deployados independentemente sem downtime:

  1. Deploy nova versão do subgrafo com mudanças de schema
  2. Gateway faz polling dos schemas dos subgrafos periodicamente (ou recebe webhooks)
  3. Gateway recompõe schema federado com novo subgrafo
  4. Se composição tem sucesso, novo schema está imediatamente disponível
  5. Se composição falha, Gateway usa último schema conhecido bom

Por segurança, implemente verificações de schema no CI:

typescriptimport { composeAndValidate } from '@apollo/federation';

async function validateSubgraph(schema: string) {
  const subgraphSchemas = await fetchAllSubgraphSchemas();
  const result = composeAndValidate(subgraphSchemas);

  if (result.errors) {
    console.error('Composição falhou:', result.errors);
    process.exit(1);
  }
}

Observabilidade e monitoramento

Arquiteturas federadas exigem observabilidade distribuída:

  • Métricas do Gateway: Latência de query por subgrafo, taxas de erro, tempo de composição
  • Métricas de subgrafos: Tempo de resolução por campo, padrões de query de banco de dados
  • Tracing distribuído: Correlacionar requisições do Gateway com traces de subgrafos usando header traceparent

Apollo Studio fornece monitoramento abrangente para Gateway e subgrafos, incluindo analytics de query, latência por campo e rastreamento de erros.

Quando Federation é excessivo

Federation adiciona complexidade. Não adote se:

  • Você tem um único serviço ou muito poucos serviços
  • Seus times são fortemente acoplados e fazem deploy juntos
  • Você não precisa de queries dirigidas por cliente (REST funciona bem)
  • Sua organização não tem expertise em GraphQL

Federation brilha quando:

  • Você tem 5+ microsserviços com cadências de deploy independentes
  • Múltiplos times frontend precisam de dados de múltiplos serviços
  • Você quer que times possuam suas fronteiras de API de ponta a ponta
  • Você pode investir em infraestrutura e expertise GraphQL

Conclusão

GraphQL Federation representa um amadurecimento da arquitetura de microsserviços. Ela reconhece que autonomia total de serviço é um mito — serviços devem colaborar — mas fornece uma forma estruturada de gerenciar essa colaboração sem criar gargalos organizacionais.

Ao adotar Federation, organizações podem dar aos times a autonomia que buscam enquanto apresentam uma API coerente e unificada a seus clientes. O Gateway cuida do trabalho sujo de orquestração e batching de queries, enquanto subgrafos focam na sua lógica de domínio.

O resultado é iteração mais rápida, melhor experiência de desenvolvedor e APIs que evoluem no ritmo das necessidades de negócio, não no ritmo de reuniões de coordenação.


Construindo uma arquitetura GraphQL federada? Fale com especialistas da Imperialis em web para projetar e implementar uma arquitetura Federation escalável que equilibra autonomia com coerência.

Fontes

Leituras relacionadas