API Testing 20 September 2019

Pruebas de carga a un servicio GraphQL con k6

Pepe Cano

La popularidad y adopción de GraphQL ha sido impresionante en los últimos años, y a medida que más usuarios empiezan a descubrir K6, hemos estado recibiendo una gran cantidad de preguntas sobre GraphQL. Con el siguiente post queremos proporcionar información útil para aquellos que empiezan a usar K6 a la hora de hacer pruebas a un servicio GraphQL.

¿Admite k6 las pruebas a un servicio GraphQL?

La respuesta es SÍ. K6 soporta las pruebas de servicios GraphQL que se ejecutan sobre HTTP o WebSocket.

Pero me gustaría profundizar un poco más en esta respuesta porque nos hemos dado cuenta de que algunos usuarios están ligeramente confundidos sobre cómo funciona GraphQL o K6.

GraphQL es un "lenguaje" de transporte independiente

GraphQL es un lenguaje para consultar y manipular las APIs; la especificación define la sintaxis para comunicarse con una API GraphQL.

Por ejemplo, dado un esquema de un API:

type Query {
me: User
}
type User {
id: ID
name: String
}

La consulta sería:

{
me {
name
}
}

GraphQL es agnóstico en cuanto a la capa de transporte; no restringe un servidor GraphQL a ejecutarse sobre un protocolo de transporte en particular. HTTP es la opción común debido a su ubicuidad, pero un servidor GraphQL podría ejecutarse sobre diferentes protocolos como:

  • HTTP, AMQP, Websockets, entre otros.
  • Protocolos de bajo nivel: TCP, UDP, gRPC, entre otros.

Por otro lado, K6, toma el papel de cliente de GraphQL, se pueden generar peticiones sobre HTTP o Websocket en el momento de escribir este post. Esto significa que K6 puede probar cualquier servidor GraphQL que se ejecute sobre uno de los protocolos de K6 soportados.

Ejemplo de una prueba de la API GraphQL de GitHub

Vamos a intentar mostrar rápidamente un ejemplo usando K6 para probar un servicio GraphQL. Para evitar la configuración y ejecución de nuestro propio servidor GraphQL, cargaremos la prueba de la API GraphQL de GitHub. Estamos eligiendo la API de GitHub porque es familiar para muchos desarrolladores, está bien documentada y tiene múltiples tipos de esquemas, consultas y mutaciones con las que podemos jugar.

Para empezar, necesitamos un Token Personal de GitHub para autenticarnos con la API de GitHub. Consulte la siguiente guía para crear un Token Personal para ejecutar esta prueba. Dependiendo de las peticiones de nuestra prueba, tu token necesitará diferentes permisos o alcances. Para el siguiente ejemplo, tu token necesita los siguientes permisos:

  • Acceder a los repositorios públicos: repo:public_repo
  • Leer y escribir discusiones de equipo: write:discussion
¿Cómo puedo crear mi primera solicitud usando GraphQL?

Debido a que la API GraphQL de GitHub se ejecuta a través de HTTP, y las consultas o mutaciones GraphQL requieren un cuerpo codificado en JSON, utilizarás la función http.post para generar peticiones que lleguen a la API.

Podríamos empezar nuestra prueba obteniendo algunos datos de la API de GitHub:

¿Cuál fue el primer issue de GitHub del proyecto K6?

El código es bastante sencillo; sólo tienes que poner tu Token en la cabecera de la Autorización, escribir la consulta GraphQL (Objeto/Repositorio/Issues) y enviarla en la petición POST.

let accessToken = 'TOKEN_DE_GITHUB';
let query = `
query FindFirstIssue {
repository(owner:"loadimpact", name:"k6") {
issues(first:1) {
edges {
node {
id
number
title
}
}
}
}
}`;
let headers = {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
};
let res = http.post('https://api.github.com/graphql', JSON.stringify({ query: query }), { headers: headers });

Ahora mismo, nuestro script de K6 se limita a llamar el endpoint para solicitar siempre los mismos datos, pero en realidad lo que queríamos era crear una prueba para replicar una interacción concreta del usuario.

Depuración de datos en la respuesta

Mientras desarrollas tu script, puede que quieras ver el contenido de la respuesta para validar los datos o utilizarlo en tu test de carga.

if (res.status === 200) {
console.log(JSON.stringify(res.body));
let body = JSON.parse(res.body);
let issue = body.data.repository.issues.edges[0].node;
console.log(issue.id, issue.number, issue.title);
}

La respuesta será algo como lo siguiente:

INFO[0001] "{"data":{"repository":{"issues":{"edges":[{"node":{"id":"MDU6SXNzdWUxNzA0MzczOTY=","number":4,"title":"Deduplicate HTTP client code"}}]}}}}"
INFO[0001] MDU6SXNzdWUxNzA0MzczOTY= 0=4 1="Deduplicate HTTP client code"
Ejecutando una mutación para añadir una reacción 🎉 al primer issue de K6.

Este sencillo ejemplo pretende mostrar cómo actualizar los datos del servidor en base a los datos obtenidos de otra petición. En GraphQL, utilizarás mutaciones para modificar los datos.

Puedes leer los documentos para añadir una reacción o encontrar ejemplos para aprender la sintaxis de esta mutación. En este caso, la mutación añadir una reacción necesita el issue.id para añadir la reacción 🎉 al issue. A continuación se muestra un ejemplo:

let mutation = `
mutation AddReactionToIssue {
addReaction(input:{subjectId:"${issue.id}",content:HOORAY}) {
reaction {
content
}
subject {
id
}
}
}`;
res = http.post('https://api.github.com/graphql', JSON.stringify({ query: mutation }), { headers: headers });

Ahora, puedes ejecutar la prueba y comprobar la reacción a la emisión de K6 pasando el mouse por encima del siguiente ícono 🎉 . Aqui puedes consultar el ejemplo completo.

easygraphql-load-tester

Fue una agradable sorpresa cuando descubrimos que easygraphql-load-tester utilizaba K6. Encontrar usuarios que utilizan tu producto, especialmente de formas inesperadas y útiles, es alentador y una gran manera de aprender sobre las necesidades de nuestros usuarios.

easygraphql-load-tester es una idea genial; se trata de una librería de nodos para hacer que las pruebas de carga de GraphQL sea lo más sencillo posible. Sólo tienes que pasar tu esquema GraphQL (tipos de objetos y consultas), y creará una prueba de carga usando tus consultas de esquema.

const userSchema = fs.readFileSync(path.join(__dirname, 'schema', 'user.gql'), 'utf8');
const familySchema = fs.readFileSync(path.join(__dirname, 'schema', 'family.gql'), 'utf8');
const easyGraphQLLoadTester = new EasyGraphQLLoadTester([userSchema, familySchema]);
easyGraphQLLoadTester.k6('k6.js');
// o puedes usar
easyGraphQLLoadTester.artillery();

La reutilización de archivos de esquema es una manera inteligente y rápida de tener una prueba de carga para su backend GraphQL en funcionamiento sin siquiera escribir una sola consulta GraphQL. Además, la librería te da la posibilidad de elegir entre artillery o K6 😉 para ejecutar la prueba de carga.

Encontramos que easygraphql-load-tester es muy útil si quieres una forma rápida de crear pruebas de carga simples llamando tus consultas GraphQL.

La biblioteca no se limita a auto-generar una prueba de carga basada en sus consultas de esquema. También puedes personalizar tus peticiones de prueba de carga seleccionando o generando consultas personalizadas, así como utilizar mutaciones. Si quieres saber más sobre estas características, consulta la siguiente documentación.

Una prueba sencilla es mejor que no hacerla

Sin embargo, easygraphql-load-tester no puede crear pruebas más realistas en las que una petición necesita alguna información de otra anterior. Volviendo a los inicios de k6, escribimos sobre este tema en nuestro manifiesto centrado en el desarrollador: "Las pruebas sencillas son mejores que no hacerlas".

Una prueba de carga de unidad es probar una sola unidad, como endpoint de una API, de forma aislada.
Una prueba de carga de escenario es para probar un flujo de interacciones del mundo real.

easygraphql-load-tester encaja en el tipo de pruebas "unit load", pero como muchas otras herramientas de pruebas, no puede crear escenarios del mundo real como:

  • Iniciar sesión y obtener su token de usuario.
  • Usar el token para listar elementos.
  • Hacer una acción sobre un elemento.

Hemos proporcionado arriba un ejemplo de K6 para este tipo de pruebas y le recomendamos que use K6 para eso.

Conclusión

Cada vez recibimos más preguntas sobre GraphQL:

Intentamos aclarar algunas de las cuestiones anteriores en este post. Ahora bien, recapitulando, probar GraphQL con k6 es tan sencillo como generar una petición con datos.

El post también incluye un ejemplo básico para dar un punto de partida para probar un servicio GraphQL con K6. Hemos querido ser breves, pero las posibilidades son infinitas, el script de K6 y las opciones de K6 permiten ejecutar un amplio abanico de pruebas de rendimiento de distintos tipos.

< Back to all posts