Skip to content

API Testing

API testing exercises the service through its interface rather than its UI. You send requests (or invoke RPCs) and assert on status codes, headers, payload shape, business rules and error contracts. Because an API is the contract every client depends on, it is the highest leverage place to test behaviour.

client ──request──▶ API ──▶ service ──▶ datastore
◀─response── (status, body, headers, errors)

Three interface styles dominate, and each needs a different testing stance:

  • REST — resource URLs, HTTP verbs, JSON. Validate status codes, media types and schema.
  • GraphQL — one endpoint, typed schema, arbitrary queries. Validate resolvers, nullability, error paths and query depth limits.
  • gRPC — protobuf contracts, HTTP/2 streams. Validate message schemas, status codes and deadline/cancellation behaviour.

Use it for

  • Verifying the request/response contract every client relies on
  • Business rules the UI hides or cannot reach (pagination edges, auth scopes, rate limits)
  • Fast, stable regression coverage that runs without a browser
  • Validating error handling: 4xx messages, 5xx behaviour, validation failures

Avoid it when

  • You are re-asserting the same rule already covered by a faster unit or integration test
  • You need to verify rendering, accessibility or interaction — that is end-to-end
  • You want to test internal implementation detail rather than the published interface
Tool Ecosystem Notes
Postman / Newman Any GUI authoring plus CLI runner for CI
REST Assured Java Fluent DSL over REST endpoints, JUnit-friendly
Karate Java / JVM BDD-style API tests, built-in mocking and Gatling perf
Schemathesis Python Property-based, generates cases from OpenAPI/Swagger
Bruno Any Git-friendly, offline, plain-text collections
Robot Framework + RequestsLibrary Python Keyword-driven REST testing, easy to read and extend
Playwright APIRequestContext Multi Reuse browser fixtures for pure API checks
grpcurl / ghz Go gRPC reflection calls and load testing
Dredd Node Validate implementation against API Blueprint/OpenAPI
Terminal window
npm install -D vitest supertest
npm install -g newman
newman run collection.json
import request from 'supertest';
import { app } from '../src/app';
it('rejects a user without a name', async () => {
const res = await request(app).post('/users').send({ name: '' });
expect(res.status).toBe(422);
expect(res.body.errors[0].field).toBe('name');
});
  • Assert on the contract, not the implementation. Check status, schema and semantics the client was promised, not private field ordering.
  • Validate the schema automatically. Run Schemathesis, Dredd or JSON-schema checks so coverage scales beyond hand-written cases.
  • Test the unhappy paths. Empty bodies, wrong types, missing auth, oversized payloads and rate limits are where APIs break.
  • Keep collections in version control. Bruno and Newman make collections diffable; stop sharing exported Postman JSON by email.
  • Seed and clean via the API itself where possible, and isolate data per run so tests are order-independent.
  • Do not chase 100 percent endpoint coverage. Prioritise endpoints on critical client paths.

Self-assessment quiz

Pick one answer per question, then press Check answers.

  1. What does API testing primarily verify?
  2. Which tool generates property-based cases from an OpenAPI schema?
  3. Which Python library drives REST tests in a keyword-driven style?
  4. For a GraphQL API, what deserves explicit testing?
  5. Why keep API collections in version control?