Why a tester should know APIs
Most applications have two parts: the interface the user sees, and the server the interface talks to through an API. When you click “Save”, the browser sends a request to the API and the server replies whether it worked.
API tests are faster and more stable than UI tests, and they check things you can’t see in the interface: whether the server rejects invalid data when someone bypasses validation in the browser, and whether it refuses to hand out other people’s data. That is why API testing is a separate, important part of testing, not an add-on to UI tests.
This is the fifth part of the “Testing from scratch” series.
Look at the API in your browser
Before you open any tool, open any web application, press F12 and go to the Network tab. Do something, e.g. search for a product. Requests will appear in the list. Click one of type fetch or xhr and look at the Headers, Payload and Response tabs. That is the API the application uses.
This tab is useful every day: when something doesn’t work, you can see straight away whether the problem is in the interface or the server returned an error.
What a request consists of
| element | example | meaning |
|---|---|---|
| method | POST | what you want to do |
| URL | https://api.example.com/orders | on which resource |
| headers | Content-Type: application/json, Authorization: Bearer ... | extra information, including who you are |
| body | {"productId": 15, "quantity": 2} | the data you send |
The most common methods:
- GET retrieves data;
- POST creates a new resource;
- PUT replaces the whole resource;
- PATCH changes part of a resource;
- DELETE deletes a resource.
What a response consists of
A response has a status code, headers and a body, usually in JSON. The status code tells you how the request ended:
| code | meaning |
|---|---|
| 200 OK | success |
| 201 Created | a new resource was created |
| 204 No Content | success, no body in the response |
| 400 Bad Request | invalid request, e.g. a required field is missing |
| 401 Unauthorized | not authenticated: the server doesn’t know who you are |
| 403 Forbidden | not authorised: the server knows who you are, but you have no access |
| 404 Not Found | no such resource |
| 409 Conflict | a conflict, e.g. the email is already taken |
| 500 Internal Server Error | an unhandled error on the server side |
An important rule: a user error is a 4xx code. If you send invalid data and get a 500, that is a defect, because the server didn’t handle a situation it should have expected. A fuller table of codes is in the interview questions.
An exercise in Postman
JSONPlaceholder, a free API with sample data, is good for learning. It accepts every request but saves nothing permanently, so you can’t break anything.
Step 1. Fetch data. In Postman create a new GET request to https://jsonplaceholder.typicode.com/posts/1 and click Send. You will get a 200 code and this structure:
{
"userId": 1,
"id": 1,
"title": "...",
"body": "..."
}
Step 2. Create a resource. Change the method to POST, the URL to https://jsonplaceholder.typicode.com/posts, and in the Body tab choose raw and JSON:
{
"title": "My first test",
"body": "Post body",
"userId": 1
}
The response should have a 201 code and contain the data you sent with a new id.
Step 3. Add tests. In the Scripts tab (Tests in older versions) add checks that Postman runs after every response:
pm.test("status 201", () => {
pm.response.to.have.status(201);
});
pm.test("returns the sent title and a new id", () => {
const json = pm.response.json();
pm.expect(json.title).to.eql("My first test");
pm.expect(json.id).to.be.a("number");
});
pm.test("responds in under 1 s", () => {
pm.expect(pm.response.responseTime).to.be.below(1000);
});
Step 4. Tidy up. Save the requests in a collection and move the base URL to an environment variable, e.g. {{baseUrl}}/posts. You can then run the whole collection and export it for your portfolio.
What to check in an API
A 200 code is only the beginning. For every endpoint, go through this list:
- Happy path: valid data, correct result, correct code.
- Validation: missing required fields, wrong type (text instead of a number), values that are too long, empty values.
- Non-existent resources: an ID that doesn’t exist should return 404, not 500.
- Authentication: a request without a token and with an expired token.
- Authorisation: whether changing the ID in the URL, e.g.
/orders/1001instead of/orders/1000, gets you someone else’s order. This is one of the most serious bugs found in APIs. - Duplicates: what happens when you send the same POST request twice.
- Side effects: whether the data was really saved in the database, whether the email was sent.
- Error content: whether the message is understandable and doesn’t reveal technical details of the server.
What next
Once Postman holds no secrets for you, the next step is checking the shape of responses, i.e. API contract testing, and automating API tests in code. The last part of the series covers first steps in automation.