CodeGym /Cursos /Módulo 5. Spring /Lección 300: Análisis de errores típicos al desarrollar G...

Lección 300: Análisis de errores típicos al desarrollar GraphQL API

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

GraphQL es una herramienta potente para construir APIs, pero, como sabes, con gran poder viene también gran responsabilidad. Incluso los desarrolladores más experimentados cometen errores al diseñar esquemas GraphQL, data fetchers y queries. En esta lección vamos a analizar los errores más comunes, ver cómo evitarlos y repasar buenas prácticas para escribir un GraphQL API de calidad y eficiente.


Errores típicos al diseñar el esquema

Esquema incompleto o excesivo

Diseñar el esquema es una especie de arte; es fácil pasarse o, al contrario, crear un esquema que no cubre la funcionalidad necesaria.

Ejemplo de error:


type Query {
  userProfile: UserProfile
}

type UserProfile {
  id: ID
  firstName: String
  lastName: String
  age: Int
  hobbies: [String]
  contactInfo: String
}

Parece normal, pero ¿y si contactInfo contiene datos sensibles? Un esquema así puede provocar fácilmente una filtración.

Cómo evitarlo:

  • Diseña esquemas minimalistas y aislados.
  • Aplica el enfoque need-to-know al exponer datos y evita "sobrealimentar" al cliente con información innecesaria.

Ejemplo de esquema corregido:


type Query {
  userProfile: UserProfile
}

type UserProfile {
  id: ID
  firstName: String
  lastName: String
  age: Int
  hobbies: [String]
}

type PrivateUserInfo {
  contactInfo: String
}

Ahora la información confidencial está separada en un tipo distinto, que solo puede ser entregado a usuarios autorizados.

Estructuras profundamente anidadas (problema N+1)

Error:

Si tu esquema tiene anidaciones demasiado profundas, el cliente puede pedir enormes cantidades de datos en una sola query potente.

Ejemplo:


query {
  users {
    id
    posts {
      id
      comments {
        id
        text
      }
    }
  }
}

Si hay miles de usuarios, cada uno con decenas de posts, y cada post con cientos de comentarios, esta query puede dejar tu servidor en bancarrota.

Cómo evitarlo:

  • Limita la profundidad de las queries usando plugins o middleware.
  • Usa Batch Loading para eliminar consultas duplicadas.

Errores en el procesamiento de datos

Problemas de rendimiento (error N+1)

Problema: Un error común al usar GraphQL es que al recuperar datos relacionados las consultas a la base de datos empiezan a dispararse como una ametralladora.

Ejemplo:


@QueryMapping
public List<User> users() {
    return userService.getAllUsers();
}

@QueryMapping
public List<Post> posts(@Argument("userId") String userId) {
    return postService.getPostsByUser(userId);
}

Cada usuario podría iniciar una consulta separada para obtener sus posts relacionados. Si hay 100 usuarios, se ejecutarán 100 consultas SQL a la base de datos.

Corrección: Usamos DataLoader:


@Bean
public DataLoaderRegistry dataLoaderRegistry() {
    DataLoaderRegistry registry = new DataLoaderRegistry();

    DataLoader<String, List<Post>> postLoader = DataLoader.newMappedDataLoader(userService::getPostsForUsers);
    registry.register("posts", postLoader);

    return registry;
}

Ahora para 100 usuarios se hará solo 1 batch-query.

Excepciones no manejadas

Error: tu data fetcher lanza excepciones no manejadas que van al log del servidor y potencialmente revelan información interna del sistema.

Ejemplo:

@QueryMapping
public User user(@Argument("id") String id) {
    return userService.findById(id);
}

Si no se encuentra el usuario con el id dado, lo más probable es que salte un NullPointerException.

Solución: Envuelve los errores en excepciones personalizadas.


@QueryMapping
public User user(@Argument("id") String id) {
    return userService.findById(id).orElseThrow(() -> new CustomException("User not found"));
}

Errores de seguridad de datos

Falta de límites por profundidad y complejidad de las queries

GraphQL permite al cliente tanta flexibilidad que algún despistado puede enviar queries con profundidad de 1000 niveles o una complejidad que supera el límite de 100000 operaciones.

Solución:

  • Activa límites de profundidad y complejidad de las queries.
  • Usa librerías como graphql-java o plugins para configurar los límites.

GraphQLSchema schema = GraphQLSchema.newSchema()
    .query(QueryType)
    .maxQueryDepth(10)
    .maxQueryComplexity(1000)
    .build();

Falta de comprobación de autorización y autenticación

Error: A menudo se olvida validar la autorización de los usuarios al ejecutar queries.

Solución:

Usa DataFetchEnvironment para validar el usuario actual:


public CompletableFuture<User> user(DataFetchingEnvironment env) {
    String token = env.getContext();
    if (!authService.isAuthenticated(token)) {
        throw new AuthenticationException("Invalid token");
    }
    return userService.getUserByToken(token);
}

Errores en las pruebas

No cubrir con tests queries complejas

Muchos se quedan en tests para queries simples, pero olvidan probar queries con fragments, campos anidados y mutaciones.

Solución:

Crea tests para todos los escenarios de uso. Por ejemplo, usa MockMvc para tests de integración:


mockMvc.perform(post("/graphql")
        .content("{\"query\":\"{ user { id, name } }\"}")
        .contentType(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.data.user.id").exists());

Errores en el diseño del API

Duplicación de lógica en esquemas y resolvers

Error: La lógica se repite para el mismo comportamiento dentro del GraphQL API.

Solución:

Usa una capa de servicios para manejar la lógica de negocio y adáptala al contexto de la query dentro de los resolvers.


Práctica: corregir errores

Para terminar la lección veamos algunos ejercicios:

  1. Corrige el escenario con el problema N+1 usando DataLoader.
  2. Implementa un límite de profundidad para las queries.
  3. Escribe tests de integración para una mutación con objetos anidados.

En un proyecto real esto te dará un API más estable, y los clientes te lo agradecerán.

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