I’m sure you’re here because you need to load test a Json Rest API. It’s not a surprise since Rest API are increasingly popular these days.
That’s the purpose of this guide: help you load test a Json Rest API through a concrete example, OctoPerf’s Json Rest API.
And this guide will completely get you through the following knowledge:
No theory here, only practice: everything is based on a realistic Rest API (not a dummy example). You can download the sample JMX while following the tutorial.
Ready to learn? Let’s go!
Rest API Login
OctoPerf platform is based on a Json Rest API. We’re going to see how you can simulate a login to our API using JMeter.
But how does the authentication works? How can we simulate a login with JMeter? Most Rest APIs work with the following login workflow:
- Login using an HTTP POST Request by providing
username
and password
,
- Receive a temporary authentication token for later requests to identify yourself,
- Send the auth token within subsequent requests, typically via HTTP Headers like
Authorization: Bearer AUTH_TOKEN
.
So does the OctoPerf API. That’s pretty close to Oauth Authentication.
Login API Specs
First, let’s see how we can login on OctoPerf Application. Thankfully, our API has a Swagger Specification: Swagger is a tool for providing a Rest API Documentation.
Doc specifying how to login via OctoPerf’s API
Good! Now let’s examine the request we need to forge using JMeter:
-
Http Method: must be a POST request, with some post parameters, (see GET vs POST)
-
Http Scheme: https
since our Rest API is secured by SSL,
-
Hostname: api.octoperf.com
,
-
Path: /public/users/login
(Login endpoint path),
-
Post Parameters:
- username: the account username, if you don’t have any you can easily signup here,
- password: the associated password.
We should then receive from the server a Json Response which should look like:
1
2
3
|
{
"token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
|
See the token here? That’s something we’ll use later to identify ourselves on the Rest API. But, first let’s take a look at the JMeter HTTP Request.
Executing Login
Login on OctoPerf via the Rest API
Here we have our Login Http Request ready to be sent to our servers. I’ve just hidden the sensitive information, but that’s basically your account information here. In order to debug the login, we’re going to use the View Results Tree Listener.
Login request sent to the server
As we can see, the sent request is a POST form-urlencoded which contains our login and passwords. Nothing difficult here! Now, we’re interested in the Json Response sent by the server.
Response received from the server
Fine! Now we’ve received the Authentication Token, we can extract it to reuse it in subsequent requests.
Token Based Authentication is a simple mechanism where a token uniquely identifies a user session. We need to handle this dynamic parameter
to properly simulate a user interacting with our Json API.
To extract the authentication token from the server response, we’re going to use JMeter JsonPath Extractor. The process of extracting a variable from a response works as follows:
- The server sends back a response to our login request,
- A post-processor, like the JsonPath Extractor is executed afterwards,
- the extractor extracts part of the server response and put it into a variable like
${token}
.
Extracting Authentication Token from server response
We have configured the JMeter Json Extractor with those settings:
- Name of created variables:
token
, which will result in a reusable variable with the syntax ${token}
,
- Json Path Expressions:
$.token
, Refer to Example JsonPath Expressions for more info,
- And Match Nr: simply
1
, for the first occurence. But we could leave it blank.
See where I placed the extractor? Right under the login
HTTP request. Let’s also add a Debug Sampler to see if the variable is extracted correctly.
Enabling Debug
Enabling JMeter variables in Debug Sampler
By setting JMeter Variables to true
, we enable the sampler to output the variables during the test run.
Token is successfully extracted from server response using Json Extractor
Great! The Json extractor is perfectly working. It extracts the value of the token
field from the Json response. We can now use the ${token}
expression in subsequent requests to perform authenticated requests.
Let’s see how we reuse this token to tell our Rest API that we’re a given user.
Reinjecting Auth Token
Our Rest API has many endpoints which require authentication. Those endpoints provide data like user workspaces, projects, virtual users and more. To access user-protected endpoints, one must:
- Login to get an authentication token (like we did previsouly),
- Send the auth token within an
Authorization: Bearer TOKEN
http request header, for each subsequent request.
That’s exactly what we’re going to do here.
Retrieving User Workspaces
We’re now particularly interested in querying the workspaces of our user. This is part of the Workspaces API Endpoints.
Workspaces Rest API Endpoint from Swagger API Docs
We’re going to perform a GET
request to the endpoint with path /workspaces/member-of
. It should return a Json response containing the user workspaces. Here is an example response:
1
2
3
4
5
6
7
8
9
10
|
[
{
"created": "2018-04-23T12:40:00.133Z",
"description": "This is my personal workspace.",
"id": "workspaceId",
"lastModified": "2018-04-23T12:40:00.133Z",
"name": "Personal",
"userId": "myUserId"
}
]
|
Let’s create an HTTP request within JMeter to query those. That’s pretty simple like shown on the screenshot below.
Call member-of endpoint from JMeter
Here we have setup an HTTP request to query the workspaces of the user:
- Http Method: must be a GET request, no parameters involved,
- Http Scheme:
https
since our Rest API is secured by SSL,
- Hostname:
api.octoperf.com
,
- Path:
/workspaces/member-of
.
Is it finished? Not yet. For now, if we don’t provide the authentication token, the server will reject our request.
Server returns an error
The server rejects the request with an Http 4xx error: 401 Unauthorized
.
Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided.
We need to provide the authentication token by including an Authorization
header within the request. How? By adding an HTTP Header manager to the request.
Setting extracted token within Authorization header
Remember: we have previously extracted the token
from the /public/users/login
endpoint server response. Now, it’s time to reuse it to retrieve access protected resources:
- First, add an Http Header Manager under the getWorkspaces HTTP Request,
- Add the
Authorization
header, with value Bearer ${token}
.
Got the workspaces from the server
Nice! It’s working now! We’ve got all the workspaces which belong to the logged user.
Authorization header has been sent within the request
The authorization header has been successfully included within the request headers. But, one thing that’s pretty annoying is: The Json is not formatted correctly. Why?
Most servers send json in compact format, skipping indentation. This is done for performance reason (reduces bandwidth usage and server CPU usage)
To overcome this issue, the JSON Formatter PostProcessor does the job very well.
JMeter Json Formatter Post-Processor
Json is pretty printed now!
Now, we can leverage the power of the Json Assertion (introduced in JMeter 4.0) to check the server response.
Using Json Assertion
We’re going to make sure the server response contains the Personal
workspace. That’s a job for the Json assertion. To add a Json assertion, right-click on the HTTP Request sampler, then select Add > Post Processor > Json Assertion
.
Configuration
Asserting the response contains a Personal workspace
The Json assertion is configured as following:
- Assert Json Path Exists:
$.[1]['name']
refers to the second workspace returned, and takes its name
,
- Additionally Assert Value: Check to enable checking the value of the
name
field,
- Expected Value: should be
Personal
.
Execution
Suppose we assert the expected value is Other
instead of Personal
.
The Json Assertion Fails when looking for workspace named ‘Other’
As expected, the assertion fails with the following message:
1
2
3
|
Assertion error: false
Assertion failure: true
Assertion failure message: Value expected to be 'Other', but found 'Personal'
|
Of course, you’re not constrained to use only Json Assertion. you can also use The JMeter Response Assertion if you want to. It’s even beneficial in terms of performance, because the Response Assertion consumes less CPU / memory resources than the Json assertion according to our Assertions Performance Comparison Table.
Simulating Dynamic Behavior
Now that we know how to login on a Json Rest API and send requests to access protected endpoints, let’s see how we can simulate a dynamically behaving
user with JMeter.
That’s the final part of this tutorial:
- First, we’re going to extract a random workspace ID, (will be
${workspaceId}
)
- Second, we’re going to query the projects of that workspace using the endpoint
/projects/by-workspace/${workspaceId}/DESIGN
.
OctoPerf’s Projects Rest API Endpoints
The last Rest API endpoint interests us. We’re going to call it from JMeter, but first we need to extract a random workspaceId.
Extracting random workspaceId
The extractor is configured as a post-processor of the getWorkspaces
request with the settings:
- Name of created variables:
workspaceId
,
- Json Path Expressions:
$..id
,
- Match No:
0
, which is random.
This extracts a random workspaceId, and puts it in the ${workspaceId}
variable.
Querying Projects
Finally, we need to query the projects according to the previously extracted workspaceId
. For this purpose, I have duplicated and modified the previous request to gain some time.
Querying projects with workspaceId variable
Here we have setup an HTTP request to query the projects of a workspace:
- Http Method: must be a GET request, no parameters involved,
- Http Scheme:
https
since our Rest API is secured by SSL,
- Hostname:
api.octoperf.com
,
- Path:
/design/projects/by-workspace/${workspaceId}/DESIGN
. DESIGN
states for projects enclosed within a workspace. (and not within a result, which would be RESULT
)
I guess we’re ready to run a quick iteration to try this out!
Viewing Results
Execution results in querying the projects
If we execute the user multiple times, we see that the response varies depending on the random workspaceId being extracted.
Final Words
JMeter is really well suited for Rest API Testing, especially those based on the Json Format. Testing Json APIs with JMeter is really easy.
Basically, if you master the JMeter components mentioned above, you’re good to go!
If you want to dig further, I strongly suggest you to read our articles about:
Feel free to share this guide if you found it useful!
This is great and really helpful, thanks for uploading this.
Thank you a lot!!! Bearer was soo important.
This is really great. Helped a lot. Kept all practically required things at one place.
I am following your blog for writing my perf test plan. I am using 5.0 JMeter and i see PATCH call in the http request .But when i am using that , I get an error as below. Can you please help me if there is a solution for this ? Error : java.net.ProtocolException: Invalid HTTP method: PATCH at java.net.HttpURLConnection.setRequestMethod(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection.setRequestMethod(Unknown Source) at org.apache.jmeter.protocol.http.sampler.HTTPJavaImpl.setupConnection(HTTPJavaImpl.java:193) at org.apache.jmeter.protocol.http.sampler.HTTPJavaImpl.sample(HTTPJavaImpl.java:536) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:67) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1231) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1220) at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:622) at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:546) at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:486) at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:253) at java.lang.Thread.run(Unknown Source)
In reply to Roopa
Hi Roopa, You have selected Java http engine in your HTTP request which doesn’t support PATCH requests.
Dear Jerome, Hope you doing good. I have an issue with Jmeter scripting due to the encryption we are now using for rest api application. As we have issued certificates and API Keys to external client connection to our application so all messages are now coming through encryption. The Jmeter tool cannot simulate or act as a third party due to this certificate requirement and thus not able to simulate as end user work.
The one solution is disable certificates but we cannot do this. So when we running our scripts getting HTTP 400 error so please suggest step wise solution to override this problem if exist.
Appreciate your kind support.
Regards Nurul Khan
In reply to Nurul Khan
Hi Nurul,
You need to configure JMeter to use your own keystore, which should contain your client certificate.
Thank you Jerôme, very clear and helpful tutorial
Thank you very much! Really helpful guide on how to setup a test plan for REST APIs
Hi I am following this blog to create Load Test for Rest API and this blog is helpful but I have an additional requirement. My Authorization Token expires every 30 minutes so in your example, is there any way I can execute the login request (to get new Authorization token) every 30 minutes while the other requests are executing continuously without stopping them so that after every 30 minutes the getWorkspaces request gets new Authorization token from login request. It would be even better if you have way to put getWorkspaces & getprojects into different Thread Group and access the new Auth token from login Thread Group every 30 minutes.
Any help would be appreciated. Than you In Advance.
Hi, I have integrated JMeter API test with Jenkins. I am able to publish the JMeter report. Now I want to publish pass-fail (no of test cases passed/failed) in Jenkins UI only without going to external report. How can I do that? Any help would be appreciated. Thank you In Advance.
Excellent article. I learn a lot of new things from this article and resolve my problem which i was facing since many days. God bless you. Keep helping the world through your words. Thanks.