Cómo testear una GraphQL API con Cypress

Resumen

Testear una API GraphQL con Cypress es más sencillo de lo que parece: no necesitas librerías externas ni plugins, solo entender cómo se estructura la query y cómo enviar la petición. Aquí aprenderás a escribir tu primer test contra un endpoint GraphQL usando PokeAPI como ejemplo, ideal si ya trabajas con REST y quieres dar el siguiente paso.

¿Qué diferencia hay entre GraphQL y una API REST al testear?

La gran ventaja que ofrece GraphQL frente a REST es el control sobre los datos que recibes. En una API REST, si el endpoint te devuelve veinte campos y solo necesitas tres, tienes que filtrar en el front. Con GraphQL, tú defines exactamente qué propiedades quieres en la respuesta y el servidor te entrega solo eso.

Esto se conoce como solución al overfetching. Si no necesitas el conteo o la propiedad next, simplemente las quitas de la query y desaparecen del response.

¿Qué es el overfetching? Es cuando una API te devuelve más información de la que realmente necesitas. GraphQL lo evita porque tú defines en la query qué campos quieres recibir.

¿Cómo se estructura una query de GraphQL?

Una query en GraphQL se parece a una función: tiene un nombre, recibe parámetros y devuelve un conjunto de propiedades específicas. En el playground de PokeAPI puedes ver cómo se arma una petición que recibe un limit tipo entero y un offset para paginar resultados.

Dentro del cuerpo de la query accedes al recurso, en este caso pokemons, le pasas las variables y declaras qué propiedades quieres de vuelta: count, next, results, name, lo que necesites.

Para empezar tu test, crea un archivo llamado graphql.cy.js y dentro un bloque describe con el texto "Testing GraphQL", seguido de un it que diga "You must make a query with GraphQL".

¿Cómo guardo la query dentro del test?

Declara una constante con backticks para preservar saltos de línea y espacios. Las template strings son clave aquí porque GraphQL es sensible al formato de la query.

javascript const graphqlQuery = query pokemons($limit: Int, $offset: Int) { pokemons(limit: $limit, offset: $offset) { count next results { name } } };

Luego defines las variables que tu query va a consumir en un objeto aparte:

javascript const graphqlVariables = { limit: 20, offset: 0 };

¿Por qué una consulta GraphQL se envía como POST?

Aunque estés recuperando información, toda petición GraphQL viaja sobre el protocolo HTTP usando el método POST. La razón es que estás enviando una query y un conjunto de variables en el cuerpo de la petición, no solo consultando un recurso fijo por URL.

¿Por qué GraphQL usa POST en vez de GET? Porque envías la query y las variables en el body de la petición, indicando qué datos quieres incluir o excluir. Aunque obtengas información, técnicamente estás mandando datos al servidor.

La estructura del body en una petición GraphQL sigue una convención: una propiedad query con el string de la query y una propiedad variables con el objeto de parámetros.

javascript cy.request({ method: 'POST', url: 'https://...graphql-pokeapi...', body: { query: graphqlQuery, variables: graphqlVariables } }).then((response) => { cy.log(response); });

¿Cómo valido la respuesta de una API GraphQL?

Toda respuesta de una API GraphQL devuelve una propiedad llamada data dentro del body. Ahí vive toda la información que pediste. En este caso, dentro de data aparece pokemons, y dentro de pokemons están count, next, message y el array results.

Para hacer la aserción, accedes al primer elemento del array de resultados y validas su nombre:

javascript expect(response.body.data.pokemons.results[0].name).to.equal('bulbasaur');

Si pasas un offset en cero y un limit de 20, el primer Pokémon que debería retornar es Bulbasaur, seguido de Ivysaur, Venusaur y así sucesivamente. Si el test falla, revisa que el nombre esté escrito correctamente, en minúsculas y sin espacios.

¿Qué son las mutations y por qué no las probamos aquí?

GraphQL maneja dos tipos de operaciones principales: queries para leer y mutations para crear, modificar o eliminar datos. PokeAPI no expone mutations públicas por una razón obvia: cualquiera podría borrar Pokémon o alterar la base de datos compartida.

Si quieres practicar mutations, el reto es montar tu propia base de datos GraphQL local donde puedas probar operaciones de escritura sin afectar servicios públicos.

Conceptos y habilidades clave de la clase

  • Query GraphQL [00:38]: estructura tipo función con nombre, parámetros tipados y campos de retorno definidos por el cliente.
  • Overfetching [01:24]: problema de las APIs REST que GraphQL resuelve permitiéndote pedir solo los campos necesarios.
  • Template strings con backticks [02:08]: forma correcta de almacenar la query preservando formato.
  • Variables de GraphQL [02:31]: objeto con los parámetros que la query consume, como limit y offset.
  • Petición POST [02:55]: todas las requests de GraphQL viajan como POST porque envían query y variables en el body.
  • Convención del body [03:25]: el cuerpo de la petición debe tener las propiedades query y variables.
  • Propiedad data en la respuesta [04:08]: contenedor estándar donde GraphQL devuelve toda la información solicitada.
  • Aserción sobre arrays anidados [04:35]: validar response.body.data.pokemons.results[0].name para confirmar el primer resultado.
  • Mutations [05:18]: operaciones de escritura que no se prueban en APIs públicas por riesgos de integridad.

¿Ya probaste tu primer test contra una API GraphQL? Cuéntame en los comentarios qué endpoint usaste y si lograste montar tu propia base con mutations.