API Testing for QA Engineers: The Complete Guide (2026)
If you only test through the UI, you are catching bugs at the most expensive layer. API testing lets you verify business logic, data validation, and integrations faster, more reliably, and earlier in the development cycle. It is one of the highest-value skills a QA engineer can add, and it is increasingly expected in interviews at every level.
Companies with mature API testing practices catch 60% more defects before they reach the UI layer, according to SmartBear's State of API 2024 report. That is not just faster feedback — it is fundamentally cheaper to fix.
This guide covers everything you need to go from "I have never tested an API" to "I can build and maintain an API test suite."
What Is API Testing?
An API (Application Programming Interface) is how different parts of a software system communicate. When you click "Add to Cart" on a website, the frontend sends an HTTP request to an API endpoint like POST /api/cart/items. The server processes the request and sends back a response.
API testing means sending requests directly to these endpoints and validating the responses — bypassing the UI entirely. You are testing the engine, not the dashboard.
Why API testing matters more than ever
Modern applications are built as collections of services that communicate through APIs. A single user action on a website might trigger 5-10 API calls behind the scenes. If you only test through the browser, you are testing one surface while the real complexity lives underneath.
API tests are:
- Faster. A browser test that takes 30 seconds might test the same logic as an API test that takes 200 milliseconds
- More stable. No CSS selectors to break, no animations to wait for, no flaky tests from timing issues
- More precise. You can test specific error conditions, edge cases, and data states that are hard to trigger through the UI
- Earlier in the pipeline. API tests can run before the frontend is even built
HTTP Fundamentals You Need to Know
Before writing API tests, you need to understand the protocol they use.
HTTP Methods
| Method | Purpose | Example |
|---|---|---|
| GET | Retrieve data | Get a user's profile |
| POST | Create a new resource | Create a new order |
| PUT | Replace an existing resource entirely | Update a user's full profile |
| PATCH | Partially update a resource | Change just a user's email |
| DELETE | Remove a resource | Delete a saved address |
Status Codes
Status codes tell you what happened. Memorize the important ones:
- 200 OK — The request succeeded
- 201 Created — A new resource was created (expect this after POST)
- 204 No Content — Success, but nothing to return (common after DELETE)
- 400 Bad Request — The request was malformed (missing fields, wrong types)
- 401 Unauthorized — Authentication is missing or invalid
- 403 Forbidden — Authenticated but not authorized for this action
- 404 Not Found — The resource does not exist
- 409 Conflict — The request conflicts with current state (duplicate email, etc.)
- 422 Unprocessable Entity — Validation failed (email format wrong, etc.)
- 500 Internal Server Error — Something broke on the server
A strong API test suite covers not just the happy path (200/201) but all the error paths (400, 401, 403, 404, 422). That is where the real bugs live.
Request and Response Structure
Every HTTP request has:
- URL — The endpoint you are calling (
https://api.example.com/users) - Method — GET, POST, PUT, DELETE, etc.
- Headers — Metadata like
Content-Type: application/jsonandAuthorization: Bearer <token> - Body (for POST/PUT/PATCH) — The data you are sending, usually JSON
Every response has:
- Status code — What happened
- Headers — Metadata about the response
- Body — The data returned, usually JSON
Getting Started: Postman
If you have never tested an API, start with Postman. It gives you a visual interface to send requests and see responses without writing code.
- Download Postman (free)
- Find a public API to practice with (JSONPlaceholder, ReqRes, or the PetStore API)
- Send a GET request and examine the response
- Send a POST request to create something
- Try sending bad data and observe the error responses
Postman is excellent for exploration and learning. But for a real test suite that runs in CI, you need code-based tests.
Code-Based API Testing
With Playwright
Playwright is not just for browser testing. It has a built-in API testing layer that shares the same assertion library:
import { test, expect } from '@playwright/test';
test('GET /users returns a list of users', async ({ request }) => {
const response = await request.get('/api/users');
expect(response.status()).toBe(200);
const body = await response.json();
expect(body).toBeInstanceOf(Array);
expect(body.length).toBeGreaterThan(0);
expect(body[0]).toHaveProperty('email');
});
test('POST /users creates a user with valid data', async ({ request }) => {
const response = await request.post('/api/users', {
data: {
name: 'Jane Smith',
email: 'jane@example.com',
role: 'qa-engineer',
},
});
expect(response.status()).toBe(201);
const user = await response.json();
expect(user.name).toBe('Jane Smith');
expect(user.id).toBeDefined();
});
test('POST /users rejects missing email', async ({ request }) => {
const response = await request.post('/api/users', {
data: { name: 'No Email' },
});
expect(response.status()).toBe(422);
});
This is clean, readable, and runs in the same CI pipeline as your browser tests.
With Python (requests + pytest)
import requests
import pytest
BASE_URL = "https://api.example.com"
def test_get_users_returns_list():
response = requests.get(f"{BASE_URL}/api/users")
assert response.status_code == 200
users = response.json()
assert len(users) > 0
assert "email" in users[0]
def test_create_user_with_valid_data():
response = requests.post(f"{BASE_URL}/api/users", json={
"name": "Jane Smith",
"email": "jane@example.com",
})
assert response.status_code == 201
assert response.json()["name"] == "Jane Smith"
What to Test: The API Testing Checklist
For every endpoint, consider testing:
Functional tests
- Happy path with valid data returns expected status and response body
- Required fields are enforced (missing fields return 400 or 422)
- Data types are validated (string where number expected returns an error)
- Boundary values work (empty strings, maximum lengths, zero quantities)
Authentication and authorization
- Unauthenticated requests return 401
- Requests with expired tokens return 401
- Users cannot access resources they do not own (returns 403)
- Admin-only endpoints reject regular users
Error handling
- Non-existent resources return 404
- Duplicate creation attempts return 409
- Server errors return 500 with a safe error message (no stack traces leaked)
Data integrity
- Created resources can be retrieved with GET
- Updated resources reflect the changes
- Deleted resources return 404 on subsequent GET
- List endpoints support pagination correctly
Authentication in API Tests
Most APIs require authentication. The two most common patterns:
Bearer tokens. Your test setup logs in, receives a token, and includes it in subsequent requests:
test.beforeAll(async ({ request }) => {
const loginResponse = await request.post('/api/auth/login', {
data: { email: 'test@example.com', password: 'testpass' },
});
const { token } = await loginResponse.json();
// Use this token in all subsequent requests
});
API keys. Simpler — you include a static key in the header:
Authorization: Bearer sk_test_abc123
For test environments, use dedicated test accounts with known credentials. Never hardcode production credentials in your test suite.
Schema Validation
Checking that status codes are correct is the minimum. Schema validation ensures the response structure matches what the frontend expects. If the API starts returning user_name instead of userName, your browser tests might not catch it, but schema validation will.
Tools like Zod (TypeScript) or jsonschema (Python) let you define expected response shapes and validate automatically.
Building a Maintainable API Test Suite
As your suite grows, organization matters. Here is a structure that scales:
tests/
api/
auth/
login.spec.ts
register.spec.ts
password-reset.spec.ts
users/
create-user.spec.ts
get-user.spec.ts
update-user.spec.ts
orders/
create-order.spec.ts
order-lifecycle.spec.ts
helpers/
api-client.ts # Shared request helpers with auth
test-data.ts # Factories for generating test data
assertions.ts # Custom assertion helpers
Group tests by resource or domain, not by HTTP method. Create shared helpers for authentication, test data generation, and common assertions. This keeps your tests readable and reduces duplication.
API Testing in Interviews
API testing knowledge is tested heavily in QA and SDET interviews. Common questions include:
- What is the difference between PUT and PATCH?
- How do you test an API endpoint that depends on another service?
- What is contract testing and when would you use it?
- How do you handle authentication in your API test suite?
- Write a test for a POST endpoint that validates required fields
If you are preparing for interviews that include API testing, the API Mastery for QA course covers both the concepts and hands-on practice. For broader QA interview prep, AssertHired's mock interviews include an API testing category with questions based on real interview patterns.
Next Steps
- If you are new to APIs, start with Postman and a public API
- Once comfortable, move to code-based tests with Playwright or Python
- Build a test suite for a real project — even a personal one
- Add schema validation and authentication testing
- Integrate your tests into a CI pipeline
For a curated set of API testing resources and toolkits, check out the AssertHired store. Everything from beginner guides to advanced contract testing patterns, with lifetime access and free updates.