API Testing Fundamentals
APIs are the nervous system of modern applications. Learn to test them systematically — from HTTP methods and status codes to real curl commands and JSON payloads.
1 The Hook — Why This Matters
In 2022, a NZ health provider released a telehealth API so its mobile app could book appointments with doctors. The frontend team tested the happy path: create a patient, book an appointment, pay. It worked beautifully. Three weeks after launch, the backend API was still accepting invalid data that the frontend was supposed to reject.
A patient could create an account with no email address (field left empty in JSON). The app crashed trying to send a confirmation email. Another patient exploited a missing validation to book two appointments at the exact same time slot, causing scheduling conflicts in the clinic's database. The fix required an emergency hotfix and a $15,000 recall of test sessions.
A junior tester armed with curl and Postman would have caught both bugs before launch by testing the API directly — without relying on what the frontend told them. That is what this page teaches.
2 The Rule — The One-Sentence Version
Always test the API directly, not just through the user interface. Bypass the frontend and send requests directly to the endpoint.
The frontend can lie. It can validate input before sending it, reject malformed responses, or display success messages when the backend actually failed. Your job as an API tester is to verify that the API itself enforces the rules, not just the application layer. Test happy paths, error cases, missing fields, wrong data types, and edge cases directly against the API endpoint.
3 The Analogy — Think Of It Like...
Testing a bank teller window vs. testing the vault directly.
The teller window (frontend) has rules: "We only accept cheques from businesses with valid tax IDs." But what if you walk straight to the vault (API) and hand the same cheque to the manager? If the vault doesn't check the tax ID again, you have found a security hole. The teller window is part of the system, but the vault is the real defence. Test both.
4 Watch Me Do It — Step by Step
We will test a user creation API endpoint step by step using curl commands. The spec says:
POST /api/v1/users
Required fields: email, password (8+ chars), firstName, lastName
Optional: phoneNumber
Returns: 201 Created with user ID
-
Test the happy path (valid data)
Send a well-formed request with all required fields. Expect a 201 status and a JSON response with the new user ID.
curl -X POST https://api.example.co.nz/api/v1/users \ -H "Content-Type: application/json" \ -d '{ "email": "alice@example.co.nz", "password": "SecurePass123", "firstName": "Alice", "lastName": "Smith" }' # Expected response (201 Created): # {"id": "user-12345", "email": "alice@example.co.nz", "created": "2026-04-24"} -
Test missing required fields
Send requests with each required field missing. The API must reject with a 400 Bad Request and a clear error message.
# Missing email curl -X POST https://api.example.co.nz/api/v1/users \ -H "Content-Type: application/json" \ -d '{ "password": "SecurePass123", "firstName": "Bob", "lastName": "Jones" }' # Expected response (400 Bad Request): # {"error": "email is required"} -
Test invalid email format
Send emails that look invalid: missing @, missing domain, spaces, special characters. The API should reject or sanitise.
curl -X POST https://api.example.co.nz/api/v1/users \ -H "Content-Type: application/json" \ -d '{ "email": "not-an-email", "password": "SecurePass123", "firstName": "Carol", "lastName": "Davis" }' # Expected: 400 Bad Request with validation error -
Test weak passwords
Send passwords shorter than 8 characters. The API must enforce the minimum length rule.
curl -X POST https://api.example.co.nz/api/v1/users \ -H "Content-Type: application/json" \ -d '{ "email": "dave@example.co.nz", "password": "short", "firstName": "Dave", "lastName": "Lee" }' # Expected (400 Bad Request): # {"error": "password must be at least 8 characters"} - Test HTTP status codes Verify every scenario returns the correct status code. 201 for success, 400 for validation errors, 409 for duplicate email (already exists), 500 for server errors.
- Test response headers and body structure Verify the response includes Content-Type: application/json and the body is valid JSON. Check that the response matches the documented schema.
- Test authentication (if required) Try making the request without an API key or with an invalid token. The API should return 401 Unauthorized.
| Status Code | Meaning | When You See It |
|---|---|---|
| 200 OK | Request succeeded, data returned | GET request for a user that exists |
| 201 Created | Resource created successfully | POST request that creates a new user |
| 400 Bad Request | Client sent invalid data | Missing required field, invalid format |
| 401 Unauthorized | Authentication required or failed | Missing or invalid API key |
| 403 Forbidden | Authenticated but not authorised | User tries to delete another user's account |
| 404 Not Found | Resource does not exist | GET request for a user ID that doesn't exist |
| 409 Conflict | Request conflicts with existing data | Create user with email that already exists |
| 500 Server Error | Server internal error | Unhandled exception on the backend |
| 503 Service Unavailable | Server temporarily down | Database is unreachable |
JSON (JavaScript Object Notation) is the standard format for API requests and responses. Here are the basics:
| JSON Type | Example | Notes for Testers |
|---|---|---|
| String | "alice@example.co.nz" | Always quoted. Test: empty string, very long string, special characters |
| Number | 42 or 3.14 | No quotes. Test: negative, zero, decimal, very large |
| Boolean | true or false | No quotes, lowercase. Test: as strings ("true") — API should reject |
| Null | null | Represents empty/missing. Test: null vs empty string — they're different |
| Array | ["a", "b", "c"] | Ordered list. Test: empty array, wrong type in array |
| Object | {"key": "value"} | Key-value pairs. Test: missing key, extra key, wrong value type |
5 When to Use It — The Decision Tree
✅ Test API endpoints when...
- The API is public or used by mobile apps
- The spec defines request/response schemas
- Data validation happens server-side
- The API handles payment, identity, or sensitive data
- The endpoint is used by multiple client applications
- You suspect frontend validation is hiding backend bugs
❌ Don't use it when...
- The API is internal/undocumented with no contract
- You have no endpoint URL (in early design stage)
- The API is third-party and you can't modify it
- You are testing purely visual rendering
- Authentication credentials are unavailable to you
6 Common Mistakes — Don't Do This
🚫 Only testing through the frontend
I used to think: If the app accepts my input and shows success, the API works.
Actually: The frontend can validate before sending, mask errors, or retry silently. You don't know what the API is actually doing. Always bypass the UI and test the API directly with curl or Postman.
🚫 Forgetting to test error cases
I used to think: If the happy path works, the API is fine.
Actually: Error cases are where vulnerabilities hide. Test missing fields, wrong types, empty strings, null values, special characters, and values outside the documented range. The backend must reject these gracefully, not crash.
🚫 Not reading the response carefully
I used to think: If I get a 200 status, the request succeeded.
Actually: The HTTP status code is the first clue, but read the response body too. A 200 might include an error message. A 400 might have a misspelled field name. The API's error messages tell you what validation rules exist.
When API testing goes wrong
You send a request and get a cryptic 500 error with no message. The backend is crashing on your input. This is a critical bug, not a test failure. Document it with: (1) the exact curl command that triggered it, (2) the response status and body, (3) timestamp. This gives developers everything they need to reproduce and fix it.
7 Now You Try — Test a User Update Endpoint
Spec: PUT /api/v1/users/{userId} allows authenticated users to update their own profile. Fields: email, firstName, lastName, phoneNumber (optional). Cannot change email to one already in use.
Task: Write the curl command to test this scenario: Update user 123's phone number to "+64 21 555 0123". Include the Content-Type header and a valid request body.
Sample curl command:
curl -X PUT https://api.example.co.nz/api/v1/users/123 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"phoneNumber": "+64 21 555 0123"
}'
# Expected response (200 OK):
# {"id": "123", "email": "alice@example.co.nz", "firstName": "Alice",
# "lastName": "Smith", "phoneNumber": "+64 21 555 0123"}
Key points: PUT requires the Authorization header (you're authenticated). The request body only needs the field you're changing. The response includes the full updated user object.
8 Self-Check — Can You Actually Do This?
Click each question to reveal the answer. If you got all three, you're ready to practice.
Q1. What is the difference between testing through the frontend and testing the API directly?
Frontend testing only verifies what the browser does with the API response. It doesn't verify that the API itself enforces the rules. Testing the API directly (with curl or Postman) bypasses the frontend layer and tests the backend's validation, error handling, and data persistence directly.
Q2. What does a 201 status code mean, and when should you expect it?
201 Created means a new resource was successfully created and the response includes the created resource (usually with its new ID). Expect it when you POST to create a new user, product, order, etc. By contrast, 200 OK means the request succeeded but no new resource was created (GET, PUT, DELETE).
Q3. What is the difference between null, empty string, and missing field in JSON?
Missing: The key doesn't exist in the JSON object. Empty string: The key exists but its value is "". Null: The key exists and its value is null. These are three different things. A required field that is null should be rejected with a 400 error. An optional field can be null or missing.
9 Interview Prep — Know These Cold
These are questions Kiwi employers actually ask junior API testers.
Q1. Why should you test APIs directly instead of only through the frontend?
The frontend can mask backend bugs. It validates before sending, retries silently, or hides error messages. Testing the API directly ensures the backend enforces its own validation rules, handles errors gracefully, and persists data correctly. This is critical because the API might be used by mobile apps, third-party clients, or other backends that don't have the same frontend protections.
Q2. What tools would you use to test an API?
curl for quick command-line testing and automation. Postman for building collections, chaining requests, and sharing tests with the team. Bruno (open-source alternative to Postman). Thunder Client (VS Code extension). For automated tests, tools like Newman (Postman CLI), REST Assured (Java), or pytest (Python) let you run tests in CI/CD.
Q3. What makes a good API test case?
A good test case has: (1) clear input (exact URL, headers, body), (2) clear expected output (status code and response structure), (3) a specific purpose (test happy path, validate a boundary, check error handling), (4) repeatability (runs the same way every time), (5) independence (doesn't depend on other tests running first).
10 Link to Reference
Want the full HTTP method reference, REST conventions, and authentication patterns?
→ API Testing — Full Reference
Includes HTTP methods (GET, POST, PUT, PATCH, DELETE), headers, response validation, and authentication patterns.
11 Next Step
You now understand how APIs work and how to test them manually. The next level is learning to chain multiple API calls together: create a user, then use that user's ID to book an appointment, then verify the appointment exists. This is called stateful API testing.