In the previous chapter, we learned the core components to test in GraphQL and different tools to assist in testing GraphQL APIs. As much as functional testing of API is necessary, so is the Cross/non-functional testing of the APIs too. In this chapter, let’s look at some of the ways to perform load and security testing of GraphQL APIs.
Table of Contents: The Definitive Guide to Testing GraphQL API
- Introduction and getting started with GraphQL
- Testing GraphQL APIs
- You’re here → Cross Functional Testing of GraphQL APIs
In this Digital world, securing your apps is of utmost priority but often it’s not taken with proper care. The Vulnerability Database shows the list of GraphQL instances reported.
One of the main factors in adopting the GraphQL API is to avoid or replace multiple API calls with a single GraphQL API call. It is essential to include various techniques of cross-functional requirements like, performance, security, load and tracing GraphQL APIs. Let’s take a look at some of the techniques and tools that I follow to measure the metrics of APIs.
Tracing GraphQL
Monitoring GraphQL endpoint is a little tricky one, and sometimes the response time goes up high a lot due to complex queries sent to the server. We should look at monitoring the queries instead of endpoints. While monitoring is one of the critical metrics to measure performance, tracing the requests of the queries would give a lot more data and would be helpful in many ways. In fact, tracing is one of the important pillars for measuring observability along with logs and metrics. If your app is instrumented with tracing you could use tools like Zipkin or Jaeger to monitor logs and traces.
If you are using Apollo-server to build your GraphQL server, it’s easy and straight-forward. Apollo enables us to add a performance monitoring system, through a single line of configuration and brings insights about queries sent to the server.
const { ApolloServer } = require('apollo-server-express'); const server = new ApolloServer({ schema, tracing: true, });
And in fact, the Apollo-engine gives us wonderful metrics of your requests:
If you are using express-graphql like me to build GraphQL server then, the package from EasyGraphQL should be easy to integrate with:
const express = require('express'); const graphqlHTTP = require('express-graphql'); const { tracing, fieldResolver } = require('easygraphql-tracing'); const app = express(); app.use(tracing) app.use('/graphql', graphqlHTTP({ schema: MyGraphQLSchema, graphiql: true, fieldResolver })); app.listen(4000);
I’ve implemented the same in our sample repository here. I’ve also recorded a small video to demonstrate in real-time how the tracing works and you could notice the time it takes to execute the query.
❗ I also stumbled upon this wonderful work: A project showcasing benchmark of GraphQL server. So maybe pick one of the options for building your GraphQL server, amongst the list that works for you.
Performance Testing of GraphQL API
Jmeter is not new to the community and it has been around for more than a decade now. It needs no introduction and we’ll straight jump onto steps to get started. You can test for the performance of your GraphQL APIs in simple three steps:
Step 1: Create a new Thread Group and a number of Threads:
Step 2: Create an HTTP request and add the body parameters and API end-points. If you are using Postman for testing, you could retrieve the GraphQL query in proper JSON format by using code and then cURL option.
Step 3: Execute your tests within the Jmeter UI or via CLI
Step 4: Review Results
The EasyGraphQL helps us here too. They offer two packages a load-tester node module and easygraphql-lt . The latter package can be used with minimal JSON setup. Gatling is another popular open source tool in the performance testing space and you could achieve this in the same way!
Security Testing GraphQL API
Security is often considered as an after-thought process. Practically, the security practices would help avoid these issues and it should be considered on priority. Here are some of the key aspects to look at preventing hackers to send in abusive queries to your GraphQL server:
- Introspection
- Firstly, the primary step towards securing your GraphQL should start from disabling introspection queries. As this will allow hackers to get the schema and then build all possible queries and mutations then send payloads that’d crash the server. It is not easy and straight forward to disable the Introspection queries as there isn’t an option out of the box from GraphQL libraries and there are a couple of third-party OSS node modules that’d help. Apollo disables this option by default in Production. graphql-disable-introspection node module can come handy if you are allowed to use a third-party module.
- URL Route’s
- Changing the Route should be an option to consider, which allows no easy access. It is recommended using
/graphql
as an endpoint, but it’s not necessary. If constructing a well-formed query, changing the endpoint name wouldn’t hinder the API functionality or performance in any way. Disable GraphiQL IDE in production.
- Changing the Route should be an option to consider, which allows no easy access. It is recommended using
- Authentication
- Authentication with different layers like Token, Access control would help to secure access to your server. You can learn more on Authorization here. Solutions like graphql-shield should help to secure your server with auth.
- Depth/complexity
- GraphQL schemas are cyclic graphs, which possess risk and a hacker can easily induce a DDoS attack by forming queries like below; you could limit the query depth by introducing
Maximum Query Depth
and GraphQL server will accept or reject the query based on its depth.{ movies { name genre actor { age movies { name actor { id movies { id } } } } } }
- Throttling on Query complexity is one of the ways to limit abusive access to the schema. Github’s public GraphQL API is a classic example showing resource limitations.
- GraphQL schemas are cyclic graphs, which possess risk and a hacker can easily induce a DDoS attack by forming queries like below; you could limit the query depth by introducing
- Injection Attacks
- Injection attacks are very much possible like in the example below. This shows us that the validation and proper error messages are necessary for the Resolver functions.
{ movie(id:"Someid*`$"){ name genre actor{ name } } }
- Injection attacks are very much possible like in the example below. This shows us that the validation and proper error messages are necessary for the Resolver functions.
Security Audit with InQL
InQL is a Python based extension and you have two options, the Standalone UI mode and an extension that you can add to Burp Suite. InQL will help us inspect the Introspection Query
results and generate documentation and templates for all data types.
Please refer to InQL project documentation to get started. Here is how the documentation and the Burp screen looks for our sample project:
You can send this query template to Repeater and try to trigger the request. This is helpful if your GraphQL queries needed an authentication token.
Outro!
Congratulations! 🎉 You’ve made it up until here. Thank you for your patience. I hope, by now you are aware of some of the cross functional testing techniques that can be followed for GraphQL APIs. We’ve looked at how to perform Performance, Load and Security testing for your GraphQL APIs along with some tracing mechanism too. These practices would help prevent any malicious attacks and help in better performance.
This chapter ends the series of blog posts on GraphQL. I sincerely believe that this series would give some level of end-to-end testing knowledge on GraphQL.
References:
https://www.graphql.com/guides/
https://www.apollographql.com/docs/