How to Test REST APIs Step by Step

This tutorial walks through a practical REST API testing workflow using the Simple API. The Simple API does not require authentication, so we can concentrate on requests, responses, data, status codes, headers, and the evidence we collect while testing.

Our aim is to learn how the API behaves, compare that behaviour with the documentation and our expectations, and build a useful model of the application.


What You Will Practise

In this tutorial we will:

  • read the API documentation
  • send a first GET request
  • inspect a response
  • create a new item with POST
  • verify that the item was really created
  • vary the request data and headers
  • test validation errors
  • update and delete an item
  • decide what evidence to keep
  • decide what is worth automating

Each step builds on the previous one.

It is important to remember that API testing is stateful. A POST request might create data. A PATCH request might change data. A DELETE request might remove data. We are not just issuing requests, we are testing a System and we need to check that the system state changes and is reflected in the responses.


Start With a Practice API

For this tutorial, use the Simple API:

The main endpoint we will use is:

/simpleapi/items

The Simple API models store inventory items. Each item has fields such as:

  • id
  • type
  • isbn13
  • price
  • numberinstock

The id is generated by the server. When we create an item, we should not send an id in the request body.

The isbn13 value must be unique. This makes it a good field for testing because it creates a real data rule that we can check.


Read the Documentation First

Before sending requests, read the documentation and build a small model of what the API claims to support.

Look for:

  • endpoints
  • HTTP methods
  • required fields
  • optional fields
  • field types
  • status codes
  • response formats
  • error responses
  • headers such as Accept and Content-Type

The SimpleAPI has two official documentation sources:

For the Simple API, the documentation tells us that we can work with a collection of items and individual item resources.

Collection endpoint:

/simpleapi/items

Individual item endpoint:

/simpleapi/items/{id}

There is also a helper endpoint that returns a random ISBN:

/simpleapi/randomisbn

Use the documentation as a starting point, not as proof, and certainly not as a limit (always test beyond the documentation). Having said that,one of the jobs of API testing is to compare the documented behaviour with the actual behaviour.

If you want more background on the concepts, read the reference pages:


Send a First GET Request

Start with a read-only request.

GET https://apichallenges.eviltester.com/simpleapi/items
Accept: application/json

Try it in the built-in HTTP client:

GET /simpleapi/items to list Simple API items

Use the In Browser tab to send the request from this page. The client also has cURL and wget tabs if you want to generate a command-line version of the same request.

Check the response headers as well as the body. Headers are part of the API behaviour.

A successful response should return a status code like:

HTTP/1.1 200 OK

Then inspect the response.

Ask:

  • did the API return 200?
  • did the response include Content-Type: application/json?
  • is the response body valid JSON?
  • does the body contain an items collection?
  • do the items have the fields described in the documentation?
  • are the field types what we expected?

This first request gives us a baseline. We now know the API is reachable, it can return data, and we have some example items to compare with the documentation.


Generate Test Data

To create a new item, we need a unique isbn13.

The Simple API has an endpoint for this:

GET https://apichallenges.eviltester.com/simpleapi/randomisbn

Try it in the built-in HTTP client:

GET /simpleapi/randomisbn to generate an ISBN

Copy the returned ISBN and use it in the next request.

Good test data is deliberate. We are not just filling in fields so the request works. We are choosing values that help us learn something.

For a first valid create request, keep the data simple:

  • type: choose one valid type such as book
  • isbn13: use a unique value
  • price: use a small positive number
  • numberinstock: use a small whole number

Create an Item with POST

Use POST on the collection endpoint to create a new item.

POST https://apichallenges.eviltester.com/simpleapi/items
Content-Type: application/json
Accept: application/json

{
  "type": "book",
  "isbn13": "1234567890123",
  "price": 2.00,
  "numberinstock": 3
}

Try it in the built-in HTTP client:

POST /simpleapi/items to create a Simple API item

Use the fresh ISBN value returned by /simpleapi/randomisbn when you run the request. The values above are examples of the shape of the request. If the ISBN already exists, the API should reject it.

The built-in client uses a fresh generated ISBN for the POST body. After a successful POST, it remembers the created item id so the following example clients can use it.

For a successful create request, check:

  • status code is 201 Created
  • response body is JSON
  • response body contains the new item
  • the server generated an id
  • the response includes a Location header
  • the Location header points to the new item
  • the content-type header is application/json
  • there is a content-length header that seems accurate

The Location header is useful because it tells us where the new resource can be found.

For example:

Location: /simpleapi/items/123

Do not stop at the POST response. The response says the item was created, but good testing verifies the system state afterwards.


Verify the Created Item with GET

Use the id from the POST response, or the path from the Location header, to retrieve the item.

GET https://apichallenges.eviltester.com/simpleapi/items/{id}
Accept: application/json

Try it in the built-in HTTP client after you have created an item:

GET /simpleapi/items/{id} to retrieve the created item

The built-in client uses the last item id created from this page. If you are using another client, replace {id} with the real id from the POST response.

Check:

  • status code is 200 OK
  • id matches the created item
  • type matches the value we sent
  • isbn13 matches the value we sent
  • price matches the value we sent
  • numberinstock matches the value we sent
  • also double check the headers are what you expect

This is a small but important testing pattern:

  • perform an action
  • observe the response (the full response, body and headers)
  • make another request to check state

For create, update, and delete operations, the follow-up check often finds issues that the first response does not reveal.


Vary One Thing at a Time

After the happy path works, start varying the request.

Change one thing at a time so that the result is easier to understand.

Useful variations include:

  • remove a required field
  • send the wrong data type
  • use a duplicate isbn13
  • send an invalid type
  • send a negative price
  • send a very high price
  • send numberinstock as a string instead of a number
  • omit the Content-Type header
  • ask for XML with the Accept header
  • use an HTTP verb that is not supported on the endpoint

For example, numberinstock should be an integer. This request sends it as a string:

POST https://apichallenges.eviltester.com/simpleapi/items
Content-Type: application/json
Accept: application/json

{
  "type": "book",
  "isbn13": "1234567890124",
  "price": 2.00,
  "numberinstock": "3"
}

The API should reject this because "3" is text, not a JSON number.

Try the invalid request in the built-in HTTP client:

POST /simpleapi/items with numberinstock as a string

When the API rejects input, inspect the response just as carefully as you inspect a successful response.

Ask:

  • is the status code appropriate?
  • does the response body explain the problem?
  • is the error message useful?
  • is the error response format consistent?
  • did the API avoid creating or changing data?

Variation testing with invalid data (often called 'Negative testing') is not only trying to triggering an error condition. We want to make sure the API can handle it and responds with the correct status codes and messages describing the error. We don't really want to see the API fail - if it does then we raise a defect.


Test Duplicate Data

The Simple API requires isbn13 to be unique.

That gives us a useful data-state test:

  1. create an item with a new isbn13
  2. create another item with the same isbn13
  3. check that the second request is rejected
  4. check that only one item exists with that ISBN

The second POST should not silently create duplicate data.

Try the duplicate ISBN check in the built-in HTTP client after you have created an item:

POST /simpleapi/items with the previous ISBN to trigger duplicate validation

This type of test is common in real APIs.

Examples:

  • email address must be unique
  • username must be unique
  • product SKU must be unique
  • booking reference must be unique
  • account number must be unique

Whenever the API has a uniqueness rule, test both the allowed case and the rejected case.


Test Update Behaviour

After creating an item, try changing it.

The Simple API supports update operations on an individual item endpoint:

/simpleapi/items/{id}

Use PUT when you want to send a full replacement representation:

PUT https://apichallenges.eviltester.com/simpleapi/items/{id}
Content-Type: application/json
Accept: application/json

{
  "type": "dvd",
  "isbn13": "1234567890123",
  "price": 4.56,
  "numberinstock": 8
}

Use the same isbn13 value as the item you created earlier unless your test is deliberately checking ISBN validation.

Try the PUT in the built-in HTTP client:

PUT /simpleapi/items/{id} to replace the created item

Use PATCH when you want to change only part of the item:

PATCH https://apichallenges.eviltester.com/simpleapi/items/{id}
Content-Type: application/json
Accept: application/json

{
  "price": 9.99
}

Try the PATCH in the built-in HTTP client:

PATCH /simpleapi/items/{id} to change the price

After each update, send a follow-up GET.

GET /simpleapi/items/{id} after update to verify the current item

For PUT, check that the full item now matches the replacement data.

For PATCH, check that only the intended field changed. If you changed price, then type, isbn13, and numberinstock should still be what they were before.

This is where API testing becomes more than response checking. We are testing the behaviour of the system behind the API.


Test Delete Behaviour

Use DELETE on an individual item endpoint:

DELETE https://apichallenges.eviltester.com/simpleapi/items/{id}

Try the DELETE in the built-in HTTP client:

DELETE /simpleapi/items/{id} to remove the created item

A successful delete may return:

HTTP/1.1 204 No Content

204 means the request succeeded and there is no response body.

After the delete, send a GET request for the same item:

GET https://apichallenges.eviltester.com/simpleapi/items/{id}
Accept: application/json

Try the follow-up GET in the built-in HTTP client:

GET /simpleapi/items/{id} after delete to confirm it is gone

The API should no longer return the deleted item.

Ask:

  • does DELETE return a suitable status code?
  • does the response body match that status code?
  • can the deleted item still be retrieved?
  • can the same item be deleted twice?
  • what happens when deleting an id that never existed?

Deletion tests are often good at revealing state problems, caching issues, and inconsistent error handling.


Test Headers and Formats

Headers are part of the request data.

Two important headers for API testing are:

  • Accept
  • Content-Type

Accept tells the server what response format the client wants.

Content-Type tells the server what format the request body uses.

For example:

Accept: application/json
Content-Type: application/json

The Simple API supports both JSON and XML, so it is useful for practising format variation.

Try questions like:

  • what happens when we ask for JSON?
  • what happens when we ask for XML?
  • what happens when we send JSON but ask for XML back?
  • what happens when Content-Type is missing?
  • what happens when Content-Type says JSON but the body is not valid JSON?

Use this full client when you want to experiment with different verbs, paths, headers, query strings, and request bodies:

Experiment with Simple API headers, formats, methods, and paths

This connects directly to HTTP Basics because the API behaviour is affected by the full HTTP message, not just the URL and body.


Test Unsupported Methods

An endpoint should only support the HTTP methods that make sense for that resource.

For example, POST belongs on the collection endpoint when creating an item:

POST /simpleapi/items

But DELETE belongs on an individual item endpoint:

DELETE /simpleapi/items/{id}

It is useful to try unsupported methods and check that the API handles them cleanly.

Try an unsupported collection DELETE in the built-in HTTP client:

DELETE /simpleapi/items to check unsupported collection delete

Ask:

  • does the API return 405 Method Not Allowed?
  • does it return 501 Not Implemented for methods it does not understand?
  • does it accidentally perform an action?
  • does it return a server error?
  • does the documentation match the actual supported methods?

Read HTTP Methods and Verbs for more detail on what the common HTTP methods are expected to mean.


Keep Useful Evidence

API testing creates evidence quickly.

At minimum, keep enough information to reproduce important observations:

  • request method
  • URL
  • headers
  • request body
  • response status code
  • response headers
  • response body
  • data state before the request
  • data state after the request

An API client can save requests. A proxy can capture the actual HTTP traffic. Automation can preserve repeatable checks.

If you are using the insitu HTTP client on the page then you can use the Developer Tools in the browser to show the network tab. And you can even export the network requests as a HAR file (HTTP Archive) for later review or using in other tools.

The important point is that your evidence should show what was actually sent and what actually came back.

If a REST client hides details or changes the request, use a proxy to inspect the real HTTP traffic:

The Mirror Mode can also help when learning a tool because it shows you the request that reached the server.


Decide What to Automate

I generally recommend to perform exploratory testing first.

Use the API manually, read the responses, vary the data, and learn how the system behaves. Then automate for requests and assertions that are stable and useful.

Good first automation candidates for the Simple API include:

  • GET /simpleapi/items returns a valid item collection
  • POST /simpleapi/items creates an item with a unique ISBN
  • GET /simpleapi/items/{id} retrieves the created item
  • duplicate isbn13 values are rejected
  • invalid field types are rejected
  • PATCH /simpleapi/items/{id} changes only the intended field
  • DELETE /simpleapi/items/{id} removes the item
  • GET /simpleapi/items/{id} returns a missing-resource response after delete

I have created an example set of Java @Test methods using RestAssured which automate basic Simple API CRUD coverage.

Basic Simple API CRUD Coverage


A Simple REST API Testing Checklist

Use this as a starter checklist when practising with a new endpoint:

  • read the documentation
  • identify the resource
  • identify supported methods
  • send a valid read request
  • inspect status code, headers, and body
  • create valid data
  • verify created state with a follow-up request
  • test required fields
  • test field types
  • test malformed payloads
  • test boundary values
  • test duplicate values
  • test unsupported methods
  • test unsupported formats
  • test update behaviour
  • test delete behaviour
  • record enough evidence to reproduce findings
  • automate stable, important checks

This checklist is deliberately small. It gives you a starting point, but real testing still depends on the risks and rules of the API in front of you.


Where to Go Next

Use this tutorial as the practical path, then deepen specific areas with the reference pages:

For more hands-on practice with the same API, use:


Summary

REST API testing is a practical loop: read the documentation, send a request, inspect the response, check the state, vary the input, and record useful evidence.

The Simple API gives you a safe first place to practise because it does not require authentication and it supports common REST-style operations.

Start with GET, then create data with POST, verify the created resource, update it with PUT or PATCH, and delete it with DELETE. Along the way, test validation, headers, formats, unsupported methods, and duplicate data rules.

Practice. Keep practicing. Go deep in understanding the HTTP messages. Vary everything. Trust nothing.