RESTful API Testing Guidelines

In this blog I’ve compile some of my API testing guidelines for testing RESTful APIs. I’ve tried to cover most of the basic cases as well as some more advanced ones. When you’re testing an API, it can be hard to think of everything, so I hope my list will give you ideas and fill in some gaps in your API test plans.

To get us started, here is how the basic CRUD (Create, Read, Update, Delete) operations are typically mapped to the HTTP verbs GET, POST, PUT, and DELETE in a REST API:

  • Create – insert an entry into a database
  • Read – retrieve the entry from the database
  • Update – update the entry in the database (can be complete or partial updates)
  • Delete – delete the entry from the database

I’ll go through each of these HTTP verbs and show you how I typically test an endpoint of that type, plus I’ll show you how I ensure access control and security is properly implemented.

Testing GET Requests

Typically there will be at least two separate API endpoints that use the GET verb—one to fetch all entities and one to fetch a single entity by its ID:

GET /api/Regions //Get all regions for the current user or tenant
GET /api/Regions/{id} //Get a specific region by id

The below cases are common for testing GET APIs:

  • Requesting a list of data
  • Requesting data by valid ID
  • Requesting data by valid ID that has been soft-deleted
  • Requesting data by a non-existent ID
  • Call the GET APIs when the user is not authorized or with an invalid token

For GET requests, validate that the API responses follow these standards:

  1. When requesting valid data, the server should return the HTTP 200 OK status code for GET request along with a correctly formed JSON object in the response body
  2. For any non-existent data, the server should return the HTTP 404 status code
  3. If the API is secured, using an invalid, expired, or missing token should result in a 401 Unauthorized response

Testing POST and PUT Requests

The below cases are the most common scenarios I like to test for both POST and PUT APIs:

  • All fields are filled in with valid data
  • Only required fields are filled in with valid data
  • Not all required fields are filled in (check each missing required field, if the form is large divide it into groups)
  • If the required field is a text field, send a null or empty string (“”) as a field value
  • None of the fields are filled in
  • If there is a check for unique fields, call the POST/PUT endpoint with reused values (e.g. email address should be unique within the whole system or a department)
  • Validation of data format, depending on application requirements (e.g. max length, email format, password requirements, value ranges and etc)
  • Send a string with leading and trailing spaces (API should trim the string before inserting it into the database)
  • Call the POST/PUT API when the user is not authorized or use the invalid token

Tests for PUT Requests Only

  • Updating a record using a non-existing ID
  • Partial update (not all fields are present in JSON)
  • Update a field that is read only (e.g. one of the common cases when the email address cannot be changed after creation)
  • Send valid data that may cause a conflict (it’s a project-dependent feature, for example, if there is entity revision checking logic between the client and the server).

Some Edge Cases for POST and PUT Requests

  • If a field uses a lookup value or ID from the database, provide an invalid ID that does not exist in the database. For example, if Region references the Region table and Region IDs are from 1-10, send a value of 11.
  • If a field uses ID from the database, provide an ID of the record that is soft deleted in the database. For example, if Region references the Region table and Region IDs are from 1-10, mark the record with ID = 1 as deleted (e.g. IsDeleted, IsActive flags and etc) and send a value of 1.

  • If a field uses ID from the database, provide a valid ID that exists in the database but not available due to the filter criteria (e.g. The app has the feature – create the route for the specific region and the trip start/end can be the hubs that belong to the region. Specify the Hub Id that is not associated with the selected Region in the request body. ‘30753 California Test Hub’ is associated with ‘West region, send ‘30752 NC Test Hub’ that belongs to the different one)

  • If a field uses ID from the database, provide a valid ID that exists in the database but not available within the current department (Let’s say that the system works with Tenants, each Tenant has own associated list of items. If user is working inside Tenant 6, the entity cannot be created or updated using Tenant 12 values )

For POST and PUT requests, validate that the API responses follow these standards:

  1. A successful POST/PUT request should return an HTTP 2XX, it can be 200, 201 or 204 status and the entity is saved in database.
  2. The server can return HTTP 409 Conflict (e.g. user sends the entity with a lower revision than on the server). This is acceptable behavior and the response should return a clear error message.
  3. In case of negative testing, the server should return the HTTP 400 Bad Request. Check that the format of the returned error in the response body corresponds to the specification and contains a clear description of the error.
  4. If API returns an error, the database should remain unchanged.
  5. If the entity is created with some default values which are not part of the request body, check the related fields in database after inserting the record into the table (e.g. IsActive field exists in the database, but it’s not part of the schema. Make sure that new entities are created as active by default based on the app requirements)
  6. The tester can use their database admin tooling to define the field max length/value by looking into the table columns

Testing POST Requests Used for Getting Data

Sometimes you need to do a more complex read operation that requires a request body. GET requests don’t support any payload in the request body, so you’ll have to use a different HTTP verb, such as POST.

Here’s an example post body payload for a search request:

{
    "pagination": {
        "page": 1,
        "pageSize": 10
    },
    "search": "",
    "sort": {
        "fieldName": "",
        "direction": ""
    }
}

The below cases are the most common scenarios I like to test for POST APIs being used for this type of complex read operation:

  • Sorting a list (ASC, DESC, default sorting)
  • Pagination of the list
    a. Get the list with the limited number of entities (“pageSize”)
    b. Get the list of entities starting from the specified page number (“page”)
    c. Get the list of entities by specifying the non-existing page number (e.g. “pageCount” is 10, specify “page” as 11, API should return the empty list)

Testing DELETE Requests

Based on the project’s requirements, records may be soft- or hard-deleted. Also, the database can apply the delete as a cascading action or not. This typically happens when a child entity would otherwise lose its connection to its parent entity that is being deleted—for example, deleting order details rows when deleteing an order. Another behavior that the tester can verify to that NULL values are assigned to foreign keys when deleting breaking the link between two dependent entities.

Here are a few things to keep in mind for these different types of deleting scenarios:

  1. Soft deletes use a flag (e.g. IsDeleted, IsActive, etc) to mark the data as deleted without erasing the data itself from the DB.
  2. The soft delete should also trigger an update of LastModifiedOn, LastModifiedBy fields in the related record. This makes it possible to determine not only the fact of removal, but also the date of removal and removed by whom.
  3. Cascading deletes are when you delete a record in a table and all records associated with that record in other corresponding tables are also automatically deleted (an example is given below).
  4. Breaking the link between related entities is only suitable for optional references where the database column to which the foreign key is mapped can allow NULL values (an example of this is also given below).

Consider two separate API endpoints for DELETE—one to delete multiple entities and another one to delete a single entity by ID:

DELETE /api/Users/deletemany //Request body accepts the array of IDs
DELETE /api/Users/{id} //Request to delete a single user ID

The below cases are the most common scenarios I like to test for DELETE APIs:

  • Deleting an entity by valid ID
  • Deleting an already deleted entity
  • Deleting an entity with a non-existing ID
  • Deleting and re-adding of the same entity if there is a check for unique fields (e.g. email, entity name and etc)
  • The existing entity being deleted has no dependencies and is not used yet (e.g. create the new user)
  • The entity being deleted is a parent and has corresponding records in child tables (example of cascading delete)
    Example: The application has the feature – surveys. The survey contains questions, the survey questions can be different types and one of the survey question type is choice questions (The dependency is Survey entity > Questions > Choices).

The entity being deleted is in use
Example: The application allows to create a user (driver) and assign him to the route to be the default driver for all future trips. If the driver does not have any “In Progress” trips, then the user can be deleted.
**The app logic allows to delete it and it assigns NULL value to FR key – route.DriverId.

The entity being deleted is in use and has some associated custom results
For example: The app uses a survey feature and the users responded to the survey questions. The expected behavior of such a case should be tested according to the project specification.

Deleting multiple entities
a. Enter an array of entities IDs that should not cause an API error
b. Enter an array of entities IDs and specify some IDs that should cause the API to error. Check whether a full or partial rejection of the delete occurs, depending on the project requirements
c. Additional use case: if user can access and delete other users, try to delete themselves
d. Call the DELETE API when the user is not authorized or use an invalid token

For DELETE requests, validate that the API responses follow these standards:

  1. A successful DELETE request should return an HTTP 2XX, it can be 200, 202 or 204 status and the entity is deleted in database.
  2. If API returns an error, the database should remain unchanged. The response codes that can be returned HTTP 400 Bad Request (e.g. some app logic that does not allow to delete the entity with particular status), 403 Forbidden (users does not have permission), 404 Not Found (the resource does not exist), 409 Conflict.

Testing Access Control

Some application allow users to have the different levels of access. In that case, QA should check the responses for each of the different HTTP verbs based on the user’s role. For example: if the user can create an entity but not delete it, the DELETE API should return a HTTP 403 Forbidden response.

Here are some cases for testing APIs corresponding to different CRUD operations when the user is only authorized for certain ones:

  • The user has many roles, including the role to perform the specified CRUD operation
  • The user has other roles, but not to the specified CRUD operation
  • The user does not have any roles assigned (they are authenticated to log in, but not authorized with any roles)
  • The user ONLY has the role necessary to perform the specified CRUD operation
  • Read/Update/Delete an existing entity that is not available within the current department (Let’s say that the system works with Tenants, each Tenant has the associated entities. Verify that the user from Tenant1 with relevant assigned role cannot access the entity from Tenant2 by ID)

Conclusion

A well-tested API layer is critical to having a secure and reliable software application, so I hope that sharing my list of testing guidelines helps you to test your own RESTful APIs more thoroughly in the future.

Related Blog Posts

We hope you’ve found this to be helpful and are walking away with some new, useful insights. If you want to learn more, here are a couple of related articles that others also usually find to be interesting:

Manage Your Windows Applications With Winget

Winget, Microsoft’s native package manager for Windows 10 (version 1709 and later) and Windows 11, offers a streamlined CLI for efficient application management. This blog post introduces Winget’s installation and basic commands for installing, updating, and removing software. It highlights the tool’s ability to manage non-Winget-installed apps and explores curated package lists for batch installations. The post also recommends top Winget packages, noting some may require a paid subscription.

Read More

Our Gear Is Packed and We're Excited to Explore With You

Ready to come with us? 

Together, we can map your company’s software journey and start down the right trails. If you’re set to take the first step, simply fill out our contact form. We’ll be in touch quickly – and you’ll have a partner who is ready to help your company take the next step on its software journey. 

We can’t wait to hear from you! 

Main Contact

This field is for validation purposes and should be left unchanged.

Together, we can map your company’s tech journey and start down the trails. If you’re set to take the first step, simply fill out the form below. We’ll be in touch – and you’ll have a partner who cares about you and your company. 

We can’t wait to hear from you! 

Montage Portal

Montage Furniture Services provides furniture protection plans and claims processing services to a wide selection of furniture retailers and consumers.

Project Background

Montage was looking to build a new web portal for both Retailers and Consumers, which would integrate with Dynamics CRM and other legacy systems. The portal needed to be multi tenant and support branding and configuration for different Retailers. Trailhead architected the new Montage Platform, including the Portal and all of it’s back end integrations, did the UI/UX and then delivered the new system, along with enhancements to DevOps and processes.

Logistics

We’ve logged countless miles exploring the tech world. In doing so, we gained the experience that enables us to deliver your unique software and systems architecture needs. Our team of seasoned tech vets can provide you with:

Custom App and Software Development

We collaborate with you throughout the entire process because your customized tech should fit your needs, not just those of other clients.

Cloud and Mobile Applications

The modern world demands versatile technology, and this is exactly what your mobile and cloud-based apps will give you.

User Experience and Interface (UX/UI) Design

We want your end users to have optimal experiences with tech that is highly intuitive and responsive.

DevOps

This combination of Agile software development and IT operations provides you with high-quality software at reduced cost, time, and risk.

Trailhead stepped into a challenging project – building our new web architecture and redeveloping our portals at the same time the business was migrating from a legacy system to our new CRM solution. They were able to not only significantly improve our web development architecture but our development and deployment processes as well as the functionality and performance of our portals. The feedback from customers has been overwhelmingly positive. Trailhead has proven themselves to be a valuable partner.

– BOB DOERKSEN, Vice President of Technology Services
at Montage Furniture Services

Technologies Used

When you hit the trails, it is essential to bring appropriate gear. The same holds true for your digital technology needs. That’s why Trailhead builds custom solutions on trusted platforms like .NET, Angular, React, and Xamarin.

Expertise

We partner with businesses who need intuitive custom software, responsive mobile applications, and advanced cloud technologies. And our extensive experience in the tech field allows us to help you map out the right path for all your digital technology needs.

  • Project Management
  • Architecture
  • Web App Development
  • Cloud Development
  • DevOps
  • Process Improvements
  • Legacy System Integration
  • UI Design
  • Manual QA
  • Back end/API/Database development

We partner with businesses who need intuitive custom software, responsive mobile applications, and advanced cloud technologies. And our extensive experience in the tech field allows us to help you map out the right path for all your digital technology needs.

Our Gear Is Packed and We're Excited to Explore with You

Ready to come with us? 

Together, we can map your company’s tech journey and start down the trails. If you’re set to take the first step, simply fill out the contact form. We’ll be in touch – and you’ll have a partner who cares about you and your company. 

We can’t wait to hear from you! 

Thank you for reaching out.

You’ll be getting an email from our team shortly. If you need immediate assistance, please call (616) 371-1037.