CodeGym /Cursos /Módulo 5. Spring /Lección 292: Agrupación de consultas mediante Batch Loadi...

Lección 292: Agrupación de consultas mediante Batch Loading

Módulo 5. Spring
Nivel 16 , Lección 1
Disponible

¡Hola, futuros/as maestros/as de GraphQL! Hoy nos vamos a sumergir en el mundo de la optimización de consultas GraphQL y vamos a explicar el concepto de Batch Loading. ¿Cuántas veces habéis oído que "GraphQL arregla todo mágicamente"? Pues no hay magia, pero sí hay herramientas y patrones potentes que permiten llevar el rendimiento de una API GraphQL a otro nivel. Y una de esas herramientas es Batch Loading. ¿Listos? ¡Vamos!


¿Qué es Batch Loading?

Cuando el frontend hace una petición a GraphQL, puede solicitar una gran cantidad de datos relacionados. Ejemplo: pides una lista de usuarios, y para cada usuario necesitas su lista de posts o información sobre sus seguidores. Con una implementación estándar eso puede convertirse en decenas, o incluso cientos, de consultas a la base de datos.

Batch Loading —es decir, agrupar todas esas peticiones independientes en una sola— es una técnica para reducir el número de "llamadas" a la base de datos o a otros sistemas externos. Es literalmente la forma de "cargar todo al por mayor", en lugar de uno por uno.


¿Por qué Batch Loading es importante?

Sin Batch Loading, tu API GraphQL puede sufrir del problema conocido como N+1 Problem. Por ejemplo, imagina que pides 10 usuarios y para cada uno necesitas obtener sus 10 posts. En el peor caso esto resultaría en:

  • 1 consulta para obtener los 10 usuarios.
  • 10 consultas para obtener sus posts (1 consulta por cada usuario).

En total 1 + 10 = 11 consultas, cuando podríamos hacer solo 2 consultas grandes.

Mejoramos el rendimiento

Batch Loading ayuda a unir esas 10 consultas separadas en una sola consulta "batch" a la base de datos — resultado: menos consultas y un aumento notable del rendimiento.


Herramientas para Batch Loading

En el ecosistema GraphQL hay varias librerías populares para implementar Batch Loading. La más conocida es DataLoader. Ofrece una API cómoda para agrupar y cachear peticiones.

Spring GraphQL también soporta DataLoader de serie, así que no tenemos que reinventar la rueda.


Escenarios donde Batch Loading es útil

Veamos algunos casos típicos donde Batch Loading es especialmente valioso:

1. Datos provenientes de las mismas fuentes

Si tienes varias peticiones que usan el mismo API externo o la misma base de datos, Batch Loading es la solución ideal. Por ejemplo:


query {
  users {
    id
    posts {
      id
      title
    }
  }
}

Aquí users y sus posts se pueden extraer de la misma fuente agrupando las consultas.

2. Dependencias entre datos

Cuando campos dentro de tu schema GraphQL están relacionados o dependen unos de otros, usar Batch Loading permite evitar consultas redundantes.


Práctica: Implementación de Batch Loading en Spring GraphQL

Paso 1: Añadir DataLoader

Para empezar, primero añadimos la dependencia graphql-java-dataloader en el pom.xml:


<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-java-dataloader</artifactId>
    <version>1.4.0</version>
</dependency>

Paso 2: Crear el BatchLoader

Vamos a crear la clase UserBatchLoader, que agrupará las peticiones de usuarios para obtener sus posts:


import org.dataloader.BatchLoader;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

public class UserBatchLoader implements BatchLoader<Long, List<Post>> {

    private final PostService postService; // Supongamos que tenemos PostService

    public UserBatchLoader(PostService postService) {
        this.postService = postService;
    }

    @Override
    public CompletableFuture<List<List<Post>>> load(List<Long> userIds) {
        // Agrupamos las peticiones basadas en userId
        return CompletableFuture.supplyAsync(() -<
            userIds.stream()
                   .map(postService::getPostsByUserId) // Obtenemos los posts para cada userId
                   .collect(Collectors.toList())
        );
    }
}

Paso 3: Registrar el DataLoader

Ahora registramos nuestro BatchLoader a través de DataLoader:


import org.dataloader.DataLoaderRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class DataLoaderConfig {

    private final PostService postService;

    public DataLoaderConfig(PostService postService) {
        this.postService = postService;
    }

    @Bean
    public DataLoaderRegistry dataLoaderRegistry() {
        DataLoaderRegistry registry = new DataLoaderRegistry();
        // Registramos el loader
        registry.register("postBatchLoader", DataLoader.newMappedDataLoader(new UserBatchLoader(postService)));
        return registry;
    }
}

Paso 4: Conectar el DataLoader al Data Fetcher

Ahora tenemos que conectar nuestro DataLoader en el Data Fetcher correspondiente:


import org.dataloader.DataLoader;
import org.springframework.stereotype.Component;

@Component
public class UserGraphQLDataFetcher {

    public CompletableFuture<List<Post>> getPosts(DataLoader<Long, List<Post>> postDataLoader, User user) {
        return postDataLoader.load(user.getId()); // Usamos DataLoader para cargar
    }
}

Paso 5: Pruebas

Para ver cómo funciona Batch Loading, ejecuta la consulta GraphQL:


query {
  users {
    id
    name
    posts {
      id
      title
    }
  }
}

Ahora verás que, en lugar de N consultas separadas, la base de datos recibe 1 consulta agrupada para todos los usuarios.


¿Cómo evitar errores típicos?

Los principiantes suelen encontrarse con problemas por una configuración incorrecta de los BatchLoader. Aquí tienes algunos consejos:

  1. No olvides cachear los datos. DataLoader ya lo hace "de serie", así que evita escribir caches manuales innecesarios.
  2. La asincronía lo es todo. Aunque DataLoader funcione en modo síncrono, intenta usar CompletableFuture siempre que puedas.
  3. No uses Batch Loading para todo. Si una consulta es simple y no necesita agrupación, añade DataLoader solo donde tenga sentido.

Ventajas de Batch Loading

  • Reducción del número de consultas: minimiza las llamadas a la base de datos o a APIs externas.
  • Mejora del rendimiento: reducción de latencias.
  • Facilidad para gestionar dependencias de datos: DataLoader se encarga de agrupar los datos por ti.
  • Mejor escalabilidad: disminuye la carga en el servidor en sistemas con mucho tráfico.

¡Eso es todo por hoy! Ahora sabes cómo usar Batch Loading para optimizar tus APIs GraphQL. Y lo mejor: podrás explicarle a tus colegas por qué su aplicación va más lenta sin DataLoader (y, de paso, ofrecerles ayuda de forma elegante). ¡Suerte optimizando APIs, programadores!

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION