O Problema de Schemas GraphQL Monolíticos
Ao trabalhar com GraphQL, schemas grandes e complexos podem levar a uma baixa manutenibilidade e legibilidade. O Absinthe, um toolkit GraphQL para Elixir, oferece um mecanismo de importação de campos que permite dividir schemas em módulos menores, facilitando a organização e o trabalho em equipe.
Conceito Básico da Importação de Campos
Este mecanismo permite que tipos de objetos herdem campos de outros tipos, similar à importação de módulos em linguagens de programação. Ele é particularmente útil para schemas que acumulam muitas funcionalidades, como consultas de usuários, artigos e mais.
Exemplo Prático
Considere um schema tradicional onde todas as consultas estão definidas em um único módulo:
defmodule MeuAppWeb.Schema do
use Absinthe.Schema
query do
field :lista_usuarios, list_of(:usuario)
field :usuario, :usuario
field :criar_usuario, :usuario
field :artigos, list_of(:artigo)
field :artigo, :artigo
# Outros campos...
end
end
Com a importação de campos, podemos modularizar:
defmodule MeuAppWeb.Schema do
use Absinthe.Schema
import_types MeuAppWeb.Schema.TiposUsuario
import_types MeuAppWeb.Schema.TiposConteudo
query do
import_fields :consultas_usuario
import_fields :consultas_conteudo
end
end
Como Funciona Internamente
Durante a compilação, o Absinthe processa as importações via Absinthe.Phase.Schema.FieldImports. A lógica simplificada é:
def processa_importacoes(tipo, todos_tipos) do
Enum.reduce(tipo.importacoes, tipo, fn {origem, opcoes}, tipo_acumulado ->
tipo_origem = todos_tipos[origem] |> processa_importacoes(todos_tipos)
campos_filtrados = filtra_campos(tipo_origem.campos, opcoes)
%{tipo_acumulado | campos: campos_filtrados ++ tipo_acumulado.campos}
end)
end
Uso Avançado
Importação Seletiva
Você pode importar apenas campos específicos ou excluir alguns:
import_fields :consultas_usuario, somente: [:lista_usuarios, :usuario]
import_fields :consultas_usuario, exceto: [:usuarios_admin]
Importação em Níveis Múltiplos
Tipos podem importar campos de outros tipos que já fazem importações:
object :consultas_estendidas do
import_fields :consultas_basicas
import_fields :consultas_premium
field :recursos_extras, list_of(:recurso)
end
Importação Condicional
Com base em configurações de ambiente, você pode importar campos dinamicamente:
if VariavelDeAmbiente.get("HABILITAR_ADMIN") == "sim" do
import_fields :consultas_admin
end
Organização de Módulos
Um módulo para tipos de usuário pode ser estruturado assim:
defmodule MeuAppWeb.Schema.TiposUsuario do
use Absinthe.Schema.Notation
object :consultas_usuario do
field :lista_usuarios, list_of(:usuario) do
arg :filtros, :filtros_usuario
resolve &ResolucaoUsuario.lista/3
end
field :usuario, :usuario do
arg :id, non_null(:id)
resolve &ResolucaoUsuario.obtem/3
end
end
object :usuario do
field :identificador, :id
field :nome, :string
field :email, :string
end
input_object :filtros_usuario do
field :nome_contem, :string
field :email_contem, :string
end
end
Restrições e Limitações
A importação suporta apenas certas combinações de tipos:
- Object para Object: Suportado.
- Object para Interface: Suportado para implementação.
- Interface para Object: Não suportado.
O Absinthe detecta automaticamente importações circulares e lança eros de compilação.
Considerações de Desempenho
A importação ocorre em tempo de compilação, sem impacto na execução. Para schemas complexos, evite aninhamentos profundos e organize os módulos por domínio de negócio. Conisdere estratégias de pré-compilação para otimizar o tempo de build.
Cenários de Aplicação
Arquitetura de Microsserviços
Cada serviço pode definir seus próprios tipos, que são integrados no schema principle:
defmodule SchemaGateway do
use Absinthe.Schema
import_types ServicoUsuario.Tipos
import_types ServicoConteudo.Tipos
query do
import_fields :consultas_usuario
import_fields :consultas_conteudo
end
end
Feature Flags
Campos podem ser importados com base em recursos habilitados:
defmodule SchemaDinamico do
use Absinthe.Schema
import_types MeuAppWeb.Schema.TiposRecurso
query do
import_fields :consultas_nucleo
if Recurso.habilitado?(:nova_busca) do
import_fields :consultas_nova_busca
end
end
end
Perguntas Frequentes
A importação afeta a introspecção do GraphQL? Não, os campos importados aparecem como campos normais.
Como lidar com conflitos de campos? Campos importados posteriormente sobrescrevem os anteriores. Use nomes distintos para evitar.
As importações suportam diretivas? Sim, todas as diretivas nos campos são importadas junto.