API Testing Fundamentals: Concepts, Tools, and Best Practices
The UI is usually the last place a defect shows up, not the first place it lives. Most real logic validation, business rules, authorization sits one layer down, in the API. Testing there is faster to run, faster to write, and catches problems before they ever get a chance to surface as a confusing UI symptom.
This article covers the REST concepts every tester should know cold, how to actually design API test cases beyond "check the status code," authentication versus authorization testing, and the tools that make API testing practical day to day.
REST basics every tester needs
APIs expose resources through endpoints, and HTTP methods define the action: GET retrieves data without side effects, POST creates a new resource, PUT replaces a resource entirely, PATCH updates part of it, and DELETE removes it. Idempotency matters here, GET, PUT, and DELETE are supposed to be idempotent (calling them multiple times produces the same end state), while POST typically isn't (calling it twice usually creates two resources).
Status codes tell you the outcome: 200 (OK), 201 (Created, typically after a successful POST), 204 (No Content, common on a successful DELETE), 400 (Bad Request, malformed input), 401 (Unauthorized, missing or invalid authentication), 403 (Forbidden, authenticated, but not allowed to do this), 404 (Not Found), 409 (Conflict, the request contradicts the current state), 422 (Unprocessable Entity, well-formed but semantically invalid), and 500 (Internal Server Error). Headers like Content-Type and Authorization, and the JSON structure of the request/response body, round out what you need to read before writing a single test case.
Designing API test cases beyond "check the status code"
Positive cases confirm a valid payload returns the correct status code and a response body matching the expected schema. Negative cases test missing required fields, invalid data types, malformed JSON, and requests from an unauthorized caller. Boundary cases test things like pagination limits, maximum string lengths, and numeric edges, the same BVA thinking from test case design, applied to an API contract instead of a UI field.
Schema validation, confirming the response body's structure matches what's documented, not just that it returns something catches a category of defect that a status-code-only check completely misses. And response time checks, even simple ones, catch performance regressions before they ever reach a dedicated performance testing pass.
Authentication vs. authorization - test both, separately
Authentication confirms who you are: API keys, Bearer tokens, JWTs. Authorization confirms what you're allowed to do once you're authenticated. These require genuinely separate test cases: verify that expired or invalid tokens are correctly rejected (authentication), and separately, verify that an authenticated regular user can't hit an admin-only endpoint just because they have a technically valid token (authorization). Teams frequently test authentication thoroughly and assume authorization is automatically fine as a result it often isn't, because the two are implemented as genuinely separate checks in the backend.
Tools of the trade
Postman remains the most common starting point: collections group related requests, environments let the same collection run against dev, staging, and production with different variables, and pre-request/test scripts allow chaining logging in, capturing a token, and automatically using it in subsequent requests. Newman, Postman's CLI runner, lets those same collections run inside CI. REST Assured is the Java-based alternative, a natural fit for a team already using Java, Selenium, and TestNG, since API tests can live in the same codebase and test runner as UI automation. For advanced awareness: contract testing (tools like Pact) verifies that a service and its consumers agree on the API's shape even before full integration testing happens worth knowing conceptually even if you're not implementing it day one.
Real-World Example
Testing a cancel-booking endpoint for a service-booking platform: a valid request against an existing, cancellable booking returns 200 with the booking's status correctly updated. A request against a non-existent booking ID returns 404. A user attempting to cancel someone else's booking technically authenticated, but not authorized for that specific resource correctly returns 403, not a 404 that would leak whether the booking exists.
A request to cancel a booking that's already marked Completed returns 409, since the request conflicts with the resource's current state. And a boundary case checks that a cancellation-fee field only appears in the response when the cancellation happens within the platform's defined short-notice window confirming not just that the endpoint returns success, but that the business rule around it is implemented correctly. None of these five checks require touching the UI at all, and all five would be considerably slower and less precise to verify by clicking through the app.
Best Practices
- Validate both the status code and the response body/schema a 200 with the wrong data is still a failure.
- Always test negative and authorization scenarios explicitly, not just the happy path.
- Use environment variables so the same collection runs cleanly across dev, staging, and production.
- Script chained requests (login → capture token → use in next call) instead of manually copying tokens between requests.
- Automate API test collections into CI via a runner like Newman, so they run on every build, not only manually.
Common Mistakes to Avoid
- Mistake: Only checking the HTTP status code and ignoring the response body
Fix: Validate the actual response schema and field values, not just whether it returned 200. - Mistake: Skipping authorization tests, assuming authentication being correct is enough
Fix: Write explicit test cases confirming a user can't access resources or actions they aren't permitted to. - Mistake: Hardcoding tokens and IDs directly in requests
Fix: Chain requests with variables so tokens and IDs are captured and reused automatically. - Mistake: Only testing success-case response structure
Fix: Verify error responses have a consistent, well-formed structure too clients depend on that as much as success responses. - Mistake: Treating Postman collections as throwaway scratch work
Fix: Version-control and maintain collections the same way you would automation code.
Key Takeaways
- API testing catches many defects earlier and faster than the equivalent UI-level test would.
- Status codes are a starting point for verification, not the whole picture validates the body and schema too.
- Authentication and authorization are genuinely different concerns and need separate, explicit test cases.
- Postman and REST Assured serve the same goal from different angles; the right choice depends on your team's existing stack.
- A maintained, CI-integrated API test suite is one of the highest-leverage things a QA engineer can build.