Tutorials — 20 September 2019

Load testing GraphQL with k6

Pepe Cano

The popularity and adoption of GraphQL have been impressive in the last years, and as more users start discovering k6, we are getting more frequent questions about GraphQL. This post provides some useful information for those beginning with k6 to test a GraphQL service.

Does k6 support testing GraphQL?

The short answer is YES. k6 supports testing GraphQL services running over HTTP or WebSocket.

But I'd like to elaborate more on this answer because we've found some users were slightly confused about how GraphQL or k6 works.

GraphQL is a transport agnostic "language"

GraphQL is a language for query and manipulation of APIs; the specification defines the syntax to communicate with a GraphQL API.

For example, given an API schema like:

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

The query will be:

{
me {
name
}
}

GraphQL is transport-layer agnostic; it does not restrict a GraphQL server to run over a particular transport protocol. HTTP is the common choice because of its ubiquity, but a GraphQL server could run over different protocols like:

  • HTTP, AMQP, Websockets...
  • Low level-protocols: TCP, UDP, gRPC…

On the other side, k6, which takes the role of the GraphQL client, can generate requests over HTTP or Websocket at the time of writing this post. This means that k6 can load test any GraphQL server that runs over one of the supported k6 protocols.

Example testing the GitHub GraphQL API

Let's try to show quickly an example using k6 to test a GraphQL service. To avoid setup and run our own GraphQL server, we will load test the GitHub GraphQL API. We chose the GitHub API because it is familiar to developers, well-documented, and have multiple schema types, queries, and mutations to play with.

To start, we need a Personal GitHub Token to authenticate with the GitHub API. Follow this guide to create a Personal Token for running this test. Depending on the requests of our test, your token will need different permissions or scopes. For the next example, your token needs the following permissions:

  • Access public repositories: repo:public_repo
  • Read and write team discussions: write:discussion
How do I create my first GraphQL request?

Because the GitHub GraphQL API runs over HTTP, and the GraphQL queries or mutations requires a JSON-encoded body, you will use the http.post function to generate requests to hit the API.

We could start our test getting some data from the GitHub API:

Which was the first GitHub issue of the k6 project?

The code is quite simple; you only have to set your Token on the Authorization header, write the GraphQL query (Object/Repository/Issues) and send it on the POST request.

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

Right now, our k6 script is just hitting the endpoint to request always the same data, but we wanted to create a test to replicate a particular user interaction.

Debugging the response data

While developing your script, you might want to see the response content to validate the data or use it in your load test.

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

The output will be something like:

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"
Run a mutation to add a 🎉 Reaction to the first k6 issue

This simple example intends to show how to update server data based on data fetched from another request. In GraphQL, you will use mutations to modify data.

You can read the addReaction docs or find examples to learn the syntax of this mutation. In this case, the addReaction mutation needs the issue.id to add the 🎉 Reaction to the issue. Below is how it looks like:

const 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,
});

Now, you can run the test and check out the reaction to the k6 issue by hovering over 🎉. Check out the full example.

Conclusion

We are getting more frequent questions about GraphQL:

Testing GraphQL with k6 is as simple as generating a request with data. This blog also includes a basic example to give a starting point for testing a GraphQL service with k6. We wanted to keep it short, but the possibilities are endless, the k6 script and the k6 options allow running a wide range of different type of performance tests.

See also

< Back to all posts