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

Quick Example

Assert status and shape — both matter:

Core Concepts

Test types

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

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

References