Bem-vindo ao meu blog

Compartilhando conhecimento sobre tecnologia, programação e mais!

GraphQL com Spring Boot: Criando APIs Flexíveis e Eficientes

Publicado em: 31 de August de 2025 | Categorias: Java
GraphQL com Spring Boot: Criando APIs Flexíveis e Eficientes

Se você já trabalhou com APIs REST por um tempo, provavelmente já se deparou com alguns problemas clássicos: over-fetching (buscar dados desnecessários), under-fetching (múltiplas requisições para obter dados relacionados) e a constante evolução de endpoints conforme as necessidades dos clientes mudam. É aqui que o GraphQL entra em cena, oferecendo uma alternativa elegante e flexível.

O que é GraphQL?

GraphQL não é apenas mais uma tecnologia da moda - é uma linguagem de consulta e um runtime para APIs que resolve problemas reais do desenvolvimento moderno. Criado pelo Facebook em 2012 e tornado público em 2015, o GraphQL permite que os clientes solicitem exatamente os dados que precisam, nem mais nem menos.

A principal diferença em relação ao REST é a flexibilidade: em vez de ter múltiplos endpoints fixos, você tem um único endpoint que pode retornar diferentes estruturas de dados baseadas na consulta (query) enviada pelo cliente.

Vantagens do GraphQL

Flexibilidade nas consultas: O cliente define exatamente quais campos quer receber, evitando over-fetching e reduzindo o tráfego de rede.

Evolução da API sem versionamento: Novos campos podem ser adicionados sem quebrar clientes existentes, e campos deprecados podem ser mantidos por compatibilidade.

Tipagem forte: O schema do GraphQL define tipos claros, facilitando a validação e a documentação automática.

Resolução otimizada: Campos são resolvidos sob demanda, permitindo otimizações como lazy loading.

Implementando GraphQL com Spring Boot

Vamos criar um exemplo prático de uma API que gerencia empréstimos e suas parcelas. Nosso foco será demonstrar como campos específicos podem executar lógicas adicionais apenas quando solicitados.

Configuração Inicial

Adicione a dependência do GraphQL no seu projeto:

Maven (pom.xml):
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-graphql</artifactId>
    </dependency>
    
Gradle (build.gradle):
    
    implementation 'org.springframework.boot:spring-boot-starter-graphql'
    
Habilite o GraphiQL no application.properties:
    
    spring.graphql.graphiql.enabled=true
    spring.graphql.graphiql.path=/graphiql
    

Definindo o Schema GraphQL

Crie o arquivo schema.graphqls em src/main/resources/graphql/:

    
    type Query {
        emprestimo(id: ID!): Emprestimo
        emprestimos: [Emprestimo!]!
    }

    type Emprestimo {
        id: ID!
        nome: String!
        data: String!
        valor: Float!
        parcelas: [Parcela!]!
    }

    type Parcela {
        numero: Int!
        valor: Float!
        pago: Boolean!
    }
    

Records para os Dados

    
    import java.math.BigDecimal;
    import java.time.LocalDate;

    public record Emprestimo(
            Long id,
            String nome,
            LocalDate data,
            BigDecimal valor
    ) {
    }

    public record Parcela(
            Integer numero,
            BigDecimal valor,
            Boolean pago
    ) {
    }
    

Implementando os Resolvers

    
    import org.springframework.graphql.data.method.annotation.Argument;
    import org.springframework.graphql.data.method.annotation.QueryMapping;
    import org.springframework.graphql.data.method.annotation.SchemaMapping;
    import org.springframework.stereotype.Controller;
    import java.util.List;

    @Controller
    public class EmprestimoQueryResolver {

        private final EmprestimoService emprestimoService;
        private final ParcelasService parcelasService;

        public EmprestimoQueryResolver(EmprestimoService emprestimoService, ParcelasService parcelasService) {
            this.emprestimoService = emprestimoService;
            this.parcelasService = parcelasService;
        }

        @QueryMapping
        public List<Emprestimo> emprestimos() {
            return emprestimoService.findAll();
        }

        @QueryMapping
        public Emprestimo emprestimo(@Argument String id) {
            return emprestimoService.findById(Long.parseLong(id));
        }

        @SchemaMapping
        public List<Parcela> parcelas(Emprestimo emprestimo) {
            // Esta lógica só executa quando o campo 'parcelas' é solicitado na query
            System.out.println("Carregando parcelas para: " + emprestimo.nome());
            return parcelasService.findByEmprestimoId(emprestimo.id());
        }
    }
    

O @SchemaMapping usa convenções para fazer o vínculo automaticamente: o tipo do parâmetro (Emprestimo) identifica o tipo GraphQL, e o nome do método (parcelas) mapeia para o campo no schema.

Services para Lógica de Negócio

    
    @Service
    public class EmprestimoService {

        public List<Emprestimo> findAll() {
            return Mocks.EMPRESTIMOS;
        }

        public Emprestimo findById(Long id) {
            return Mocks.EMPRESTIMOS.stream()
                    .filter(emprestimo -> emprestimo.id().equals(id))
                    .findFirst()
                    .orElse(null);
        }
    }

    @Service
    public class ParcelasService {

        public List<Parcela> findByEmprestimoId(Long emprestimoId) {
            return Mocks.getParcelasByEmprestimoId(emprestimoId);
        }
    }
    

Mocks

    
    public class Mocks {

        public static final List<Emprestimo> EMPRESTIMOS = List.of(
                new Emprestimo(1L, "Empréstimo do FGTS", LocalDate.of(2023, 1, 10), new BigDecimal("15000.00")),
                new Emprestimo(2L, "Empréstimo Consignado", LocalDate.of(2023, 2, 15), new BigDecimal("20000.00")),
                new Emprestimo(3L, "Empréstimo Pessoal", LocalDate.of(2023, 3, 20), new BigDecimal("8000.00"))
        );

        private static final Map<Long, List<Parcela>> EMPRESTIMO_PARCELAS_MAP = Map.of(
                1L, List.of(
                        new Parcela(1, new BigDecimal("5000.00"), false),
                        new Parcela(2, new BigDecimal("5000.00"), false),
                        new Parcela(3, new BigDecimal("5000.00"), false)
                ),
                2L, List.of(
                        new Parcela(1, new BigDecimal("4000.00"), true),
                        new Parcela(2, new BigDecimal("4000.00"), false),
                        new Parcela(3, new BigDecimal("4000.00"), false),
                        new Parcela(4, new BigDecimal("4000.00"), false),
                        new Parcela(5, new BigDecimal("4000.00"), false)
                ),
                3L, List.of(
                        new Parcela(1, new BigDecimal("4000.00"), true),
                        new Parcela(2, new BigDecimal("4000.00"), false)
                )
        );

        public static List<Parcela> getParcelasByEmprestimoId(Long emprestimoId) {
            return EMPRESTIMO_PARCELAS_MAP.get(emprestimoId);
        }
    }
    

Testando a API

O Spring Boot disponibiliza um GraphiQL em http://localhost:8080/graphiql para testar suas queries.

Query simples (não carrega as parcelas):
    
    query {
      emprestimos {
        id
        nome
        valor
        data
      }
    }
    
Filtro por ID e com parcelas (executa a lógica adicional):
    
    query {
      emprestimo(id: "1") {
        id
        nome
        valor
        parcelas {
          numero
          valor
          pago
        }
      }
    }
    

Observe que apenas na segunda query você verá as mensagens de log indicando que a consulta das parcelas foi executada!

Vantagens Práticas Observadas

No nosso exemplo, fica claro como o GraphQL permite otimizações importantes:

  1. Lazy Loading Inteligente: As parcelas só são carregadas quando solicitadas, economizando recursos computacionais e consultas ao banco.
  2. Flexibilidade do Cliente: O frontend pode decidir quando precisa de dados detalhados (parcelas) vs. quando precisa apenas de informações básicas do empréstimo.
  3. Evolução Gradual: Novos campos podem ser adicionados ao schema sem impactar queries existentes.

Conclusão

O GraphQL com Spring Boot oferece uma combinação poderosa para criar APIs modernas e eficientes. A capacidade de resolver campos sob demanda, como demonstrado no exemplo das parcelas de empréstimo, permite otimizações significativas e maior flexibilidade para os clientes da API.

Para projetos onde a flexibilidade das consultas é importante e onde você quer evitar o over-fetching comum em APIs REST, o GraphQL é definitivamente uma tecnologia que vale a pena considerar. A integração com Spring Boot torna a implementação mais simples e aproveita todo o ecossistema já conhecido pelos desenvolvedores Java.

O código completo deste projeto de exemplo está disponível no meu GitHub.