The test pyramid for APIs
- Unit tests (many) — test business logic functions in isolation. No HTTP, no DB. Fast.
- Integration tests (medium) — test the API against a real database (Testcontainers). Verify the full stack from handler to DB and back.
- Contract tests (medium) — verify the API matches its OpenAPI spec. Pact for consumer-driven contracts across service boundaries.
- E2E tests (few) — test critical user journeys against a full deployed environment. Slow and flaky — keep these minimal.
Testcontainers for integration tests
// Spin up a real Postgres in Docker for each test suite
const container = await new PostgreSqlContainer().start();
const db = new Database(container.getConnectionUri());
Contract testing with Pact
The consumer (frontend or downstream service) defines what it expects from the API. The provider (API) verifies it can fulfil those expectations. Breaking changes are caught before deployment, not after.