Performance testing GraphQL: a look at the GraphQL HTTP Request sampler and how GraphQL requests can also be made using a HTTP Request sampler. jmeter , graphql , query , mutation , GraphQL HTTP Request Sampler , HTTp Request Sampler , JMeter 5.4 , HTTP Request Sampler , GraphQL Playground , Variables , Operations https://octoperf.com/blog/2022/02/04/graph-ql/ OctoPerf ZI Les Paluds, 276 Avenue du Douard, 13400 Aubagne, France +334 42 84 12 59 contact@octoperf.com Jmeter 1829 2022-02-04

Performance Testing GrapghQL

OctoPerf is JMeter on steroids!
Schedule a Demo

Introduction

In this Blog Post we are going to look at the GraphQL HTTP Request sampler and look at how GraphQL requests can also be made using a HTTP Request sampler in case you are for some reason restricted to an earlier version of JMeter (the sampler was only introduced in JMeter 5.4).

We will also look at some of the principles of GraphQL.

If your application under test comprises of a GraphQL service, you are going to have to understand how to test it and some of the performance considerations that surround performance testing of GraphQL.

What is GraphQL

There are many articles on GraphQL online, with this being the GraphQL homepage

In simple terms GraphQL is a query language for API’s that returns data based on your request, let’s consider an application with 2 individual API’s the first returns customer personal data such as:

  • Firstname
  • Lastname
  • Height
  • Weight

The second returns customer address details such as:

  • Address Line 1
  • Address Line 2
  • Years At Address
  • Residence Type

Now we are conscious that these are simple and not particularly likely in a real-world scenario, but they help demonstrate GraphQL.

From a development perspective let’s say you want to display a customer firstname and surname and the first line of their address on your web page then without GraphQL you would have to call your 2 individual endpoints and have 8 pieces of data returned (4 for each endpoint) and then some browser side logic or client software would need to extract the 3 pieces of data you needed.

With GraphQL you only need to request firstname, surname and address line 1 and those pieces of data are all that are returned.

Now this is a simple example, and you are probably thinking that it would just as easy to just call the 2 endpoints which is a fair point, however if your application under test has a much larger set of APIs and the data returned is more significant and you need to start performing complex joins and data aggregation on the data returned then the benefits of GraphQL become apparent.

Note that this blog post is not about the rationale behind whether your organisation should implement GraphQL or not it’s about the testing of the GraphQL queries (returns data, think GET) and mutations (updates data, think POST, DELETE, PATCH).

GraphQL Performance Testing Considerations

Test the internal APIs

We have touched on the concept that GraphQL aggregates data before returning the requested subset and therefore from a performance perspective this may be a performance bottleneck and needs to be considered when defining your performance testing.

To explore this further let’s go back to the simple example we outline at the start of this blog post.

Let’s call the customer personal details api-1 and let’s call address details api-2 and finally let’s call the GraphQL query gql-3.

If under peak levels of load and concurrency gql-3 takes 2000 milliseconds and this fails your performance requirements because you want all responses to be back in 1000 milliseconds then a worthwhile additional performance test is to test api-1, api-2 and qgl-3 all under the same load to see if it’s the GraphQL layer that does not perform or one of the individual endpoints that GraphQL calls internally.

So, if under peak load:

Service Name Response Time
api-1 1600 milliseconds
api-2 350 milliseconds
gql-3 2000 milliseconds

Then the poor performance is not GraphQL its one of the endpoints that it calls, and this is the source of the performance issues.

It is always a good idea to not only performance test GraphQL but also all the endpoints that it calls all under the same load conditions so you can accurately demonstrate where the source of any performance issues may be, should there be any.

Use accurate queries

Another consideration when performance testing GraphQL is ensuring that the request you make to GraphQL is indicative of how it will be used in production, we will use our simple example to demonstrate.

Let’s say that we do indeed only need three pieces of data from our GraphQL layer as we discussed in the earlier section entitles What is GraphQL, then in production the development teams may write a query similar to this:

1
2
3
4
5
customerDetails(customerId: 123456) {
  firstName
  lastName
  addressLine1
}

Which would call a query called customerDetails and take a parameter called customerId and then return 3 pieces of customer information.

We will discuss the structure of the GraphQL query in later sections so don’t worry if this does not make much sense now.

The thing with GraphQL is that it is possible to query it for any data attribute that it contains, and the request being made does not need to conform to any template other than the request must be syntactically correct and you must be asking for data that it knows about.

If in our JMeter test we constructed a request that requested all customer data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
customerDetails(customerId: 123456) {
  firstName
  lastName
  height
  weight
  addressLine1
  addressLine2
  yearsAtAddress
  residenceType
}

And when we ran our test under load it did not perform in line with our requirements then we would be unsure as to whether it was because of the GraphQL implementation not performing or the request we are making.

Again, in production systems the complexity of some of the queries can be high and using a query that will not be used in production can cause the application under test to work harder than it needs to, and you may be raising performance issues against conditions that will never materialise in production.

Because of the flexibility of GraphQL it is important to ensure you make you requests accurate with how they will be used in your application.

So that’s enough about the theory and things to look out for, lets look at building a test.

Building our test

We are going to start with building a GraphQL test with a HTTP Request Sampler as the GraphQL HTTP request Sampler was only introduced in JMeter 5.4 and it is possible that you may be using an earlier version of JMeter in your organisation for any number of reasons so it’s useful to understand how this can be done without the sampler that JMeter 5.4 offers.

HTTP Request Sampler

Firstly, you can see we define the Web Server details as we would do with any other request all GraphQL requests use POST and you may find that the Path is consistent for all requests but your organisations implementation may vary and these values can be easily attained from your development teams.

The part of the sampler we want to focus in on is the Body Data as this is where we define the request being sent to the server.

Let’s look at the request:

1
{"query":"{ \n customerDetails(customerId: 123456) { \n firstName \n lastName \n addressLine1 \n } \n }","variables":null,"operationName":null}

The first thing is that the whole request needs to be on a single line and cannot be spanned across multiple lines or contain any indentation.

Where a newline appears in the formatted request, we looked at earlier this must be replaced with a \n.

1
"{ \n customerDetails(customerId: 123456) { \n firstName \n lastName \n addressLine1 \n } \n }"

In the body of the request, we pass in the query name and any parameter values

1
customerDetails(customerId: 123456)

We also pass in the values we want returned from GraphQL

1
{ \n firstName \n lastName \n addressLine1 \n } \n }

The start of the request needs to contain whether it a Query or a Mutation, as we briefly discussed earlier Queries are used to fetch data and Mutations are used to modify data.

From our example we can see that we are looking to retrieve data with this at the start of our request: {"query":

At the end of the request you can see we have ,"variables":null,"operationName":null}

Now variables and operations in GraphQL are very specific to the request and at a high level are:

  • Variables as the name implies allows you to pass in data in the form of a variable so we could replace our customerId with a variable $customerId and pass the variable value in the request.
  • Operations allows you to provide a label to your query for distinguishing between similar but different requests.

These topics will not be explored in any more detail except to say that if you wish to learn about how to use them and define them this is where they are placed in your request using the JMeter HTTP Sampler.

If we run this sampler against a test endpoint, we get a response in this format.

HTTP Request Sampler Response

Where each piece of data we requested is returned to us along with the name of the query and prefixed with data to indicate it’s a data response.

This is clearly a very simple response to a very simple request, but GraphQL can return complex data types but in a structured way so the principles we have looked at here still apply and are valid.

Now we understand a bit more about how to make a request against a GraphQL service we can now look at the GraphQL HTTP Sampler that comes with JMeter 5.4.

If we populate the GraphQL HTTP Request Sampler with the same query we used in our HTTP Request Sampler this is how it would look.

GraphQL HTTP Request Sampler

We can see that there is a field where we can specify the Operation Name and a tab explicitly for Variables where in the HTTP Request Sampler, we needed to add these to the end of the request body data.

We no longer need to prefix the request with {"query": as we did in the earlier example as this is implicit in the request.

And we can layout our query in a much more readable format and avoid having to replace the newlines with a \n.

1
2
3
4
5
6
7
{
  customerDetails(customerId: 123456) {
    firstName
    lastName
    addressLine1
  }
}

Our response is identical as you would expect.

Conclusion

As the GraphQL request is fundamentally a HTTP Request you need to consider what your header looks like in terms of the Content-Type and any Authorization Tokens and any convenience sampler you may use such as HTTP Request Defaults can be used to simplify the Test Plan.

The new GraphQL HTTP Sampler does make the readability of the request much easier and you will find that you can test queries in your development GraphQL playground and then copy the queries directly into JMeter, the HTTP Request sampler does take a bit of formatting which can be time consuming if you request is large and contains a lot of elements but for anyone working on a version of JMeter without this sampler then this is your only alternative if you want to use JMeter.

The JMeter project used in this blog post can be found here.

Performance Testing GrapghQL
Tags:
Share:

Be the first to comment

Thank you

Your comment has been submitted and will be published once it has been approved.

OK

OOPS!

Your post has failed. Please return to the page and try again. Thank You!

OK

Want to become a super load tester?
OctoPerf Superman