TESTEROPS

A pragmatic approach to QA and OPS

API Testing Questions Part – 1

Here is the list of the first set of 15 questions in the API testing series. Hope you find this beneficial and use it to increase your knowledge.

  • Why API Testing?

In modern day applications, API’s are the prime medium of communication between two separate entities. A major chunk of business rules are written and exposed over API’s – may be a payment gateway or an OTP delivery system, all have certain level of API’s involved. So it becomes critical to test the API’s.

Why do we need to test them? Because

  • To validate the required functionality: API testing helps ensure that the API is functioning correctly and that it meets the requirements of the business or application. Testing validates that the API’s endpoints and functionality work as expected, and that the data passed between systems is accurate and in the correct format.
  • Early testing and defect detection – Testing APIs early in the development cycle can save time and money in the long run. By identifying issues early, they can be resolved before they become more significant and costly to fix.
  • Quicker and atomic tests: API tests are generally pretty atomic in nature, so as a result the execution time of api tests are much smaller as compared to the expensive UI tests. So it makes sense to test API’s before integration in UI.
  • Improves reliability of software systems: Since most of the software systems uses API’s. So API testing helps improve the reliability of the API, reducing the risk of errors and failures, thereby helping improving overall quality of the software system. By testing different use cases, including positive and negative test cases, the quality of the API can be improved, making it more reliable for its intended use.
  • Is there any difference between SOAP and REST API testing? If so, how?

Yes, there are some differences between SOAP and REST API testing.

SOAP (Simple Object Access Protocol) and REST (Representational State Transfer) are two popular web service protocols used for building and consuming APIs. Here are some differences between SOAP and REST API testing:

  1. Testing Approach: SOAP and REST use different data approaches. SOAP requires XML request and response messages, which are more structured and have a defined schema. On the other hand, REST uses simple HTTP requests and responses, which are more flexible and can return data in various formats, including JSON and XML.
  2. Testing Tools: SOAP requires specialised tools such as SOAPUI, which can handle XML request and response messages. REST API testing can be done using a variety of tools, including Postman, Insomnia, and cURL.
  3. Endpoint Verification: SOAP APIs use Web Services Description Language (WSDL) to define the service interface, which makes it easier to validate endpoints. REST API endpoints can be more difficult to verify because they rely on a combination of HTTP methods, URL, and query parameters.
  4. Error Handling: SOAP APIs have well-defined error handling mechanisms that use SOAP Fault messages to convey error details. REST APIs have less defined error handling mechanisms, and error messages are typically returned as HTTP status codes or response messages.

In summary, SOAP and REST API testing have some differences, primarily related to the testing approach, tools, endpoint verification, error handling. Testers need to be aware of these differences when designing and executing API tests. However at the end of the day, the primary crux is that an API – whether through SOAP or REST, should meet the defined standards of quality through some validation points, which can be defined during testing strategy or during the kick off meeting.

  • Key things you test in an API – let’s say a GET API to fetch a list of 5 records with id and name

You can read the article I published in my blog regarding what to validate in an API. That is an extensive list that we can use to validate the API and the response. But I will mention the points here in a shorter format –

  • Response code of the API
  • Time in which response is recieved.
  • Data format in which the response is recieved.
  • We will test the authentication ( if any) in the API.
  • Input validation checks
  • Error code handling
  • Data Structure and data sanctity – may be using a JSON Schema.
  • Validation of response and request headers.
  • Versioning etc.

  • GET vs POST

Both are HTTP verbs in a RESTful API world. Both serve two different purposes. GET is primarily a READ operation – used mostly to fetch data from an web server – where as POST is generally a WRITE operation. – used mostly to create a new record on the web server.

GET Example:

Let’s say you are building a weather app that retrieves the weather data for a specific city. In this case, you can use the GET method to retrieve the data from the server. The URL for the request might look like this:

GET https://api.weatherapp.com/weather?city=NewYork

will return the weather details for the city of New York which is passed as a query param. GET is an idempotent operation and can be cached.

POST Example:

Let’s say you are building a blog app, and you want to create a new blog post. You can use the POST method to send the new post data to the server. Here’s an example of how to create a new post using a REST API:

POST /api/posts HTTP/1.1
Host: myblogapp.com
Content-Type: application/json

{
  "title": "My First Post",
  "content": "This is my first blog post!",
  "author": "John Doe"
}

POST is not an idempotent operation and is generally not cached, although as per the RFC standard, it can be cached using proper mechanism.

  1. POST vs PUT vs PATCH – example for each

POST, PUT, and PATCH are HTTP methods used to send data to a server to create, update, or modify resources. Here’s an example for each method:

POST Example: Let’s say you are building an e-commerce website, and you want to create a new order. You can use the POST method to create a new order. Here’s an example:

POST /api/orders HTTP/1.1
Host: myecommerceapp.com
Content-Type: application/json

{
  "customer_name": "John Doe",
  "order_items": [
    {
      "product_id": "123",
      "quantity": 2
    },
    {
      "product_id": "456",
      "quantity": 1
    }
  ],
  "total": 100.00
}

In this example, we are sending a JSON object with the new order data to the server using the POST method. The API endpoint is /api/orders, and the host is myecommerceapp.com. The request header specifies that the content type is JSON.

The JSON object contains the data for the new order, including the customer name, order items, and total. The server can then process the request, create a new order, and return a response with the new order data.

It is imperative to note that POST is not an idempotent operation and is not cacheable either.

PUT Example: Let’s say you want to update an existing order. You can use the PUT method to update the entire order. Here’s an example:

PUT /api/orders/123 HTTP/1.1
Host: myecommerceapp.com
Content-Type: application/json

{
"customer_name": "Jane Doe",
"order_items": [
{
"product_id": "123",
"quantity": 3
},
{
"product_id": "789",
"quantity": 2
}
],
"total": 200.00
}

In this example, we are sending a JSON object with updated order data to the server using the PUT method. The API endpoint is /api/orders/123, where 123 is the ID of the order to update. The request header specifies that the content type is JSON.

The JSON object contains the updated data for the order, including the customer name, order items, and total. The server can then process the request, update the order, and return a response with the updated order data.

PUT is an idempotent operation but cannot be cached as indicated by this document.

PATCH Example: Let’s say you want to make a partial update to an existing order, such as changing the quantity of one of the order items. You can use the PATCH method to update only the specified fields. Here’s an example:

PATCH /api/orders/123 HTTP/1.1
Host: myecommerceapp.com
Content-Type: application/json

{
  "order_items": [
    {
      "product_id": "123",
      "quantity": 4
    }
  ]
}

PATCH is neither idempotent nor cacheable and is not a safe operation at all.

  • What do you mean when you say PUT is idempotent? Conditions for idempotency?

When we say PUT is idempotent than it means that multiple operations of the PUT with same resource will would yield the same impact, as that of a single request method.

You can read about the whole idempotency concept in my blog post

  • Do you follow any strategy for sending large payloads in POST.

First of all, this should not be confused with how to have a good strategy for large payloads in POST using Rest Assured. That is a separate discussion.

When sending large payloads in a POST request, it’s important to consider the limitations of the server and the network. Many servers and networks have limits on the size of data that can be sent in a single request, so it’s important to make sure that the payload is divided into manageable chunks that can be transmitted without causing timeouts or other errors.

One strategy for sending large payloads in POST requests is to use chunked encoding, which breaks the payload into smaller pieces and sends them one at a time. This can help to ensure that the server and network can handle the data, and it can also improve performance by allowing the client to start processing the data as soon as the first chunk is received.

Another strategy is to compress the payload using a compression algorithm such as gzip. This can significantly reduce the size of the payload, making it easier to send over the network and reducing the risk of timeouts or errors.

It’s also important to consider the security implications of sending large payloads in POST requests. Large payloads can be a target for attackers looking to exploit vulnerabilities in the server or network, so it’s important to make sure that the data is properly encrypted and that the server is configured to handle large requests securely.

  • Is it a good idea to have assertions for request headers when testing apis?

Yes. It is always a good idea to test the headers for the requests. It is a good practice to include tests for asserting headers in the API request and response both.

For e.g. – when sending a file upload through an API, it is always good to check that the Content-Type header in the request is not application/json – but multipart/form-data or something that accepts binary data like file.

  • How do you get a request header in Rest-Assured?

In Rest-Assured, you can validate the request header by using the header() method.

Let’s say you have a REST API endpoint /api/books that accepts a GET request with an Authorization header containing a JWT token.

import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

public class BookApiTest {

    @Test
    public void testGetBooks() {
        RestAssured.baseURI = "https://example.com";

        given()
            .header("Authorization", "Bearer your-jwt-token")
        .when()
            .get("/api/books")
        .then()
            .statusCode(200)
            .header("Content-Type", "application/json; charset=utf-8")
            .header("Cache-Control", "no-cache");
    }
}

  • If I send a text file as an input in a POST call, what will be the content-type?

When sending a text file as an input in a POST call, the Content-Type header should be set to text/plain. The Content-Type header specifies the type of data being sent in the request body. In this case, since the input is a text file, the appropriate content type is text/plain.

import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;

import java.io.File;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

public class FileUploadTest {

    @Test
    public void testUploadFile() {
        RestAssured.baseURI = "https://example.com";

        File file = new File("path/to/your/file.txt");

        given()
            .header("Content-Type", "text/plain")
            .body(file)
        .when()
            .post("/api/upload")
        .then()
            .statusCode(200)
            .body("status", equalTo("success"));
    }
}

  • Key things to test when you API response feeds into a down stream system?

When working with micro-services, if you API’s are down-stream to another system or another service, then you should keep in mind the following things-

  • Format of the response: Ensure that the API response is in the expected format, with the correct data types, field names, and structure that the downstream system is expecting. This can be done via establishing contracts between the two systems. You can also add a layer of consumer driven contract tests to ensure that the contract is not tempered due to changes in upstream.

  • Size of the response: Check the size of the response to ensure that it is not too large or too small for the downstream system to process. Test different response sizes to verify that the downstream system can handle different loads.

  • Response time: Check the response time of the API to ensure that it is not too slow for the downstream system to process. Test response times under different loads to ensure that the downstream system can handle the traffic. Always define a timeout period after which your system should be timing out if they are not able to handle a request.

  • Data integrity: Verify that the data returned in the API response is correct and accurate. Test with different input parameters to ensure that the data is consistent across different requests. Matching values against the defined contract and using a json schema can be good options here.

  • Using Proper error handling : Test error scenarios to ensure that the API response includes meaningful error messages that the downstream system can understand and handle appropriately.

  • Authentication: Verify that the API response is secure and that sensitive data is not leaked to unauthorized parties. This can be done as a part of whole testing for authentication or can be done separately as a part of security testing.

  • Compatibility: Ensure that the API response is compatible with the downstream system’s version, operating system, and other relevant parameters.

  • URI vs URL – with a simple example.

You can refer to my earlier post here that has a clear and concise example given.

  • 𝐂𝐚𝐧 𝐲𝐨𝐮 𝐞𝐱𝐩𝐥𝐚𝐢𝐧 𝐦𝐨𝐫𝐞 𝐚𝐛𝐨𝐮𝐭 𝐭𝐡𝐞 𝐉𝐖𝐓 𝐟𝐨𝐫𝐦𝐚𝐭 𝐚𝐧𝐝 𝐡𝐨𝐰 𝐢𝐭 𝐰𝐨𝐫𝐤𝐬 𝐟𝐨𝐫 𝐚𝐮𝐭𝐡𝐞𝐧𝐭𝐢𝐜𝐚𝐭𝐢𝐨𝐧 𝐢𝐧 𝐚𝐧 𝐀𝐏𝐈﹖

I will post about this soon.

  • Do you know if caching is applied in the rest api’s that you test? How do you test caching in api’s

This answer can depend on the interviewee. I’ll tell you how to test this. We should always test regarding caching in our api’s that we’re testing. A good starting point is to sit down with the development team to know if and how they are going to apply caching.

Caching in API’s can generally be identified with the Cache-Control API header in the response of the API. Here is a blog post that I wrote about this header. You can read about it and then add the respective tests in your suite to identify the cache mechanism, timeout period etc.

  • How do you test expired or invalid tokens in your API’s?

Broken authentication using token expiry can be one of the prime reasons of failing of security mechanisms in an API. It is imperative to test for expired or invalid tokens for the API’s. Let’s see how

First of all you should know how is the token expiry set in your API’s – it can be done via

  1. Expiry after a certain time period.
  2. Expiry after certain amount of hits using the token
  3. Using a combination of point 1 and 2.

So, before thinking of test cases for token expiry, confirm what you’re using for token expiry. Once you know about the mechanism, then you can think of the scenarios for token expiry

Valid Token rendered invalid

  • Generate a valid token from your API with a short expiration time.
  • Make a request to the API using the valid token to ensure it works as expected.
  • Wait until the token expires.
  • Make the same request again with the expired token to see if the API returns an error response indicating the token is invalid or has expired.
    • If the API returns an error response, it means the token validation is working correctly

For Step 1, you can request the dev team to shorten the expiration time so that you can test the expiry of token.

Invalid Token

You can also test for invalid tokens by generating a token with an incorrect signature or tampered payload. This can be done by modifying the token data before using it in a request to the API.

If the API correctly detects the tampering or signature mismatch and returns an error response, it indicates that the token validation is working correctly.

Another approach is to generate tokens without the proper mechanism. Let’s say your using a jwt in your token using a HS256 algorithm , whereas the application you have accepts token with the HS512 algo. So in this scenario you have an invalid token, which should be rejected by the API.

Another example can be a cross-env token test – where you try to use the token generated for the dev environment or prod env to test it in QA env. This should also be rejected and should be included in your tests.

Another example would be to use an empty token – no token at all – it would also be an example of invalid token

If you have a user-role defined set up, where there are different use roles and tokens are generated per role, then use can also use the permutation combination of trying to access details of role A with token of role B – as a test.

Count

If you have an API that sets the limit of how much API calls can be made to a specific API ( rate limiting ) and also if you have defined count of number how many times a token can be used, then you can use a load generator tool like k6 or jmeter or even postman to try hitting the api with same user for N+1 no of times where N is the limit of API hits.

You can then combine the invalid token and count scenarios to create test cases that suites your product or scenario.

This is not an exhaustive list – because there can be much more scenarios based on how the token expiry has been set by the development team.

This brings to an end to the first part of the series of API Testing questions. Feel free to let me know if there are some other questions that needs to be added.

%d bloggers like this: