API Testing
API tests verify that your endpoints behave correctly — returning the right status, the right body shape, the right errors, and enforcing auth — without driving a browser. They're fast, stable, and high-value: most of what users experience flows through the API, so testing it directly catches the majority of backend bugs cheaply.
The discipline that separates weak API tests from strong ones: validate the response structure, not just the status code. A 200 that returns the wrong shape is still a bug, and only an assertion on the body will catch it.
TL;DR
- Test happy paths and error cases.
- Validate response structure, not just status codes.
- Test authentication and authorization.
- Use contract testing to protect API consumers.
Quick Example
Assert status and shape — both matter:
Core Concepts
Test types
- Functional — correct behavior for given inputs.
- Integration — works with real dependencies (DB, services).
- Contract — the API matches its published specification.
- Load — performance under traffic (see Performance Testing).
What to test
Status codes ✅ · response body structure ✅ · headers (CORS, caching) ✅ · error responses ✅ · authentication/authorization ✅ · input validation ✅ · edge cases ✅.
Writing API Tests
Python (pytest + httpx)
JavaScript (Supertest)
Authentication & Authorization
Test the full matrix — no token, valid token, expired token, wrong role:
See Authentication and API Security.
Schema & Contract Testing
Validate the response against a schema rather than ad-hoc field checks:
Contract-test the whole API against its OpenAPI spec to catch drift automatically:
Best Practices
- Assert the body shape, not just the status — a wrong-shaped 200 is a bug.
- Cover the error matrix — validation failures, missing/expired auth, not-found, conflict.
- Test as a black box — real requests against a running app (see Integration Testing).
- Use schema validation to keep responses honest as code evolves.
- Contract-test when other teams/services consume your API.
Common Mistakes
Only checking the status code
Skipping the unhappy paths
FAQ
What's the difference between API testing and integration/E2E testing?
API testing exercises your endpoints directly via HTTP — fast, focused on request/response correctness, auth, and validation. Integration testing is broader (it may test API + database + services wired together). E2E testing drives the whole stack through a browser as a user would. API tests are the sweet spot for backend correctness: far faster and more stable than E2E, more end-to-end than pure unit tests. See Integration Testing.
Should I validate the full response body or just key fields?
Validate the structure meaningfully — at minimum the fields consumers depend on, ideally against a schema (Pydantic, Zod, JSON Schema). Schema validation catches accidental shape changes (renamed fields, wrong types, missing keys) that a status-code check misses, while being less brittle than asserting every value literally. It's the best balance of strictness and maintainability.
How do I test authentication and authorization?
Test the whole matrix: no credentials (expect 401), valid credentials (expect success), expired/invalid tokens (expect 401), and insufficient permissions (expect 403). Use fixtures to mint tokens for different roles. Authorization bugs — a user accessing another user's data — are high-severity, so test that an authenticated-but-unauthorized request is properly rejected, not just that auth "works."
What is contract testing and do I need it?
Contract testing verifies your API conforms to a published specification (OpenAPI/GraphQL schema) so independently-deployed consumers don't break when you change a response. Tools like Schemathesis generate tests from your spec; Pact verifies provider/consumer expectations. You need it when other teams or services depend on your API and could be broken by a silent shape change. See Microservices.
Related Topics
- REST API Design — What you're testing
- Integration Testing — Full-stack testing
- API Security — Auth and input testing
- GraphQL — Testing GraphQL APIs
- Performance Testing — Load-testing endpoints