Overview
In this article, we will be going over what API load testing is, why API load testing is important, and how to carry out load tests on our API.
An increase in users of a product can put strain on the backend services of the product. This can result in two things:
- Your backend crashes because it cannot handle that much load, showing its unreliability
- Your backend handles the increase in load from the increase in users, showing it has been optimized to handle more load.
Given this analogy, there are multiple methods that we can use to make sure we don’t end up in option one. One of the most important methods is API Load Testing.
What is API Load Testing?
API load testing is the practice of checking if your API can handle a certain amount of load. It is the process by which we replicate multiple users sending requests to your API endpoints at once.
Why perform Load Tests on your API?
There are great insights that come with load testing our API, some of which will be highlighted below:
- It enables us to determine the load tolerance of our API.
- It helps to minimize performance risks.
- It also helps us determine the drawbacks of our API before pushing it to production.
Tools for performing API load tests
There are several tools that we could use for load testing our APIs. For example we have: Locust, JMeter, Grafana K6, LoadView, and many more. Our focus will be on Locust.
Locust is an open-source API load testing framework built with python. It supports running multiple load tests over a distributed system, therefore it can be used to simulate millions of users.
Locust also provides a nice graphical user interface for viewing data metrics about our API performance.
It has been tested with Battlelog (the web application for Battlefield games) to simulate multiple users carrying out different operations, so Locust has been proven to be reliable.
How to setup Locust for API Load Testing
For the sake of carrying out our load tests, we need to create the API that we will be load testing.
Our API will consist of 3 endpoints:
- The first endpoint will return a simple “Hello World”
- The second will return the cube root of numbers between 1, and 1000.
- The last endpoint will return the square root of numbers between 1, 1000
To get started, we need to first install our dependencies, locust and flask. We can do this by using pip:
pip install locust flask
After our installation, we need to create our API endpoints. Create a new python file called main in your working directory, and add this piece of code:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World' @app.route('/cube-root/') def get_cube_root(): new_list = [x**3 for x in range(0, 1001)] return f'{new_list}' @app.route('/square-root/') def get_square_root(): new_list = [x**2 for x in range(0, 1001)] return f'{new_list}' if __name__ == '__main__': app.run()
Next, we run our development server like so:
python main.py
We can send requests to our endpoints to see our return values by opening the url in our browser like this:
HELLO WORLD
SQUARE-ROOT
CUBE-ROOT
Next, we need to create our locust.py file which will hold the code for load testing our API. After creating our file, we need to add this piece of code:
from locust import HttpUser, task class WebsiteUser(HttpUser): @task def hello_world(self): self.client.get(url='/') @task def square_numbers(self): self.client.get(url='/square-root') @task def cube_numbers(self): self.client.get(url='/cube-root')
This might look a bit confusing at first but we are going to understand each line, and what each block of code is meant to do.
At the top of our locust.py file, we first start by importing the basics like our HttpUser class followed by our task decorator.
Next, we create our WebsiteUser class that inherits the properties of our HttpUser class from the locust package.
The HttpUser class gives us the ability to create users which can send requests to any specified endpoint
Within our class, we need to define methods. These methods handle sending requests to the endpoint given. We can also create as many endpoints as we like with their respective request type, as shown below:
self.client.{method-type}(url=endpoint).
In the example above we specified two methods that handle sending GET requests to our API.
Finally, we can now run our locust file in our terminal like so:
locust -f locust.py
Once our locust script has started running, in our terminal we should an output similar to this:
[2022-06-27 17:31:33,960] 0x/WARNING/locust.main: System open file limit '1024' is below minimum setting '10000'. It's not high enough for load testing, and the OS didn't allow locust to increase it by itself. See https://github.com/locustio/locust/wiki/Installation#increasing-maximum-number-of-open-files-limit for more info. [2022-06-27 17:31:33,960] 0x/INFO/locust.main: Starting web interface at http://0.0.0.0:8089 (accepting connections from all network interfaces) [2022-06-27 17:31:33,986] 0x/INFO/locust.main: Starting Locust 2.9.0
We can see a url pointing to our locust web interface. We would need to open that url in our browser like so:
In the locust web interface, we can define the number of users we want to simulate for our load tests, also we can set the spawn rate of each user, and finally the host—the URL API we want to load test.
Let’s fill in the form with the necessary information. For this load test we would want to simulate 50 users at the spawn rate of 2 users/second, and for the host, we would add our flask API URL. After filling in our information in the fields it should look like this:
Finally, hit the Start Swarming button.
Next, we should see a screen with the tests running like so:
We can also view the charts of load tests by selecting the Charts option next to the Statistics option. These charts give insightful data on different areas of our API load tests.
TOTAL REQUESTS PER SECOND
This chart shows the total number of requests being sent to the endpoints per second.
RESPONSE TIMES
This chart shows the response time of all the endpoints.
NUMBER OF USERS
This chart shows how the users are being spawn in response to the set value of the spawn rate.
There are also ways to start our locust load testing server and get all this data in our terminal.
We can do this as follows:
locust -f locust.py --headless --users 50 --spawn-rate 2 -H http://localhost:5000
Conclusion
Thank you for sticking around till the end. We went over some of the important aspects of API load testing, and how we can perform load tests on our API using the python framework Locust. If you want to dive deeper into Locust, you can do so by going through their docs.