O GraphQL Inspector é um conjunto abrangente de utilitários projetado para auxiliar desenvolvedores na manutenção e evolução de APIs GraphQL. Suas capacidades incluem a validação de schemas, notificações de alterações, verificação de operações, detecção de mudanças incompatíveis (breaking changes) e análise de cobertura. Compreender sua arquitetura interna permite oitmizar o uso da ferramenta no ciclo de vida do desenvolvimento.
Arquitetura Modular
A ferramenta é estruturada em um modelo modular, distribuindo suas responsabilidades em diversos pacotes npm:
- Núcleo (Core): Contém a lógica fundamental para comparação de schemas, detecção de mudanças e regras de validação.
- Interface de Linha de Comando (CLI): Ponto de entrada para interações diretas, processando argumentos e executando as rotinas do núcleo.
- Sistema de Carregamento (Loaders): Abstrai a obtenção de schemas a partir de diferentes origens, como sistemas de arquivos, endpoints remotos ou repositórios Git.
- Ecossistema de Plugins: Extensões para integração contínua, como Actions para o GitHub e adaptadores para pipelines de CI.
Motor de Comparação de Schemas
A funcioanlidade central de diffing é orquestrada pelo módulo principle. O processo inicia com o parsing dos schemas, seguido pela identificação de adições, remoções e modificações em tipos, campos e argumentos. Em seguida, um pipeline de regras filtra e categoriza essas alterações.
Exemplo de implementação do motor de diff com processamento assíncrono de regras:
import { GraphQLSchema } from 'graphql';
import { Change, Rule, ConsiderUsageConfig } from './types';
import { extractSchemaChanges } from './extractor';
export async function calculateSchemaDifferences(
baseSchema: GraphQLSchema | undefined,
targetSchema: GraphQLSchema | undefined,
customRules: Rule[] = [],
usageConfig?: ConsiderUsageConfig
): Promise<Change[]> {
const rawModifications = extractSchemaChanges(baseSchema, targetSchema);
const processedModifications = await customRules.reduce(
async (accumulatorPromise, currentRule) => {
const accumulatedChanges = await accumulatorPromise;
return currentRule({
modifications: accumulatedChanges,
baseSchema,
targetSchema,
usageConfig
});
},
Promise.resolve(rawModifications)
);
return processedModifications;
}
Estratégias de Detecção
O algoritmo aplica heurísticas específicas para cada elemento do GraphQL:
- Objetos: Verifica a adição ou remoção de campos e alterações na assinatura de tipos.
- Enums: Rastreia a inserção ou exclusão de valores enumerados.
- Interfaces: Valida a conformidade das implementações e a estabilidade dos campos expostos.
Sistema de Validação de Operações
Além de comparar schemas, a ferramenta analisa as operações (queries e mutations) para garantir a saúde da API. As rotinas de validação incluem:
- Profundidade de Query: Limita o aninhamento de campos para evitar consultas excessivamente complexas.
- Análise de Complexidade: Atribui pesos aos campos para calcular o custo computacional da operação.
- Uso de Diretivas: Garante que diretivas personalizadas ou padrão estejam sendo aplicadas corretamente.
Essas regras são altamente configuráveis através de arquivos de manifesto no repositório do projeto.
Análise de Cobertura do Schema
O módulo de cobertura cruza a definição do schema com as operações executadas ou documentadas. O algoritmo percorre os documentos de operação, mapeando a frequência de uso de cada tipo e campo. O resultado é um relatório que destaca partes do schema que nunca são utilizadas, auxiliando na remoção de código morto.
Interface CLI e Integrações
A CLI utiliza bibliotecas de parsing de argumentos para expor comandos como diff, validate e coverage. Os resultados podem ser serializados em diversos formatos, incluindo JSON e HTML, para consumo por outras ferramentas.
Automação via GitHub Actions
Para integração em fluxos de Pull Request, a ferramenta oferece uma Action oficial. Abaixo, um exemplo de configuração de workflow:
name: Schema Validation Pipeline
on: [pull_request]
jobs:
verify-graphql-contracts:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Execute GraphQL Inspector
uses: graphql-inspector/action@master
with:
schema-path: 'src/graphql/schema.graphql'
fail-on-breaking: true
Consumo via API Programática
Desenvolvedores podem incorporar as funcionalidades diretamente em scripts Node.js ou aplicações. Exemplo de uso da API para comparar dois arquivos locais:
import { calculateSchemaDifferences } from '@graphql-inspector/core';
import { fetchSchemaFromSource } from '@graphql-inspector/loaders';
async function executeComparison() {
const sourceSchema = await fetchSchemaFromSource('./baseline.graphql');
const destinationSchema = await fetchSchemaFromSource('./current.graphql');
const modifications = await calculateSchemaDifferences(
sourceSchema,
destinationSchema
);
console.log(`Total de alterações detectadas: ${modifications.length}`);
console.dir(modifications, { depth: null });
}
executeComparison().catch(console.error);