API testing: what it can and cannot tell you
Testing the layer under the interface: what it is good at, what it cannot tell you, and the tools worth knowing.
An API test skips the browser. That single fact accounts for both its advantages — it is faster by an order of magnitude, it fails for exactly one reason, and it can assert on things a page never displays — and its limitation, which is that a perfectly correct API tells you nothing about whether anyone can use the product.
The most valuable use of an API in a browser suite is not testing it at all. It is arriving at the state a test needs. Creating an order through fourteen UI steps tests the order-creation journey once and then pays for it in every test that needs an order to exist. Creating it with one HTTP call, and testing the journey in the one test that is about the journey, is usually the largest single speed-up available to a mature suite.
import { test, expect } from '@playwright/test';
// Arrange over HTTP, act in the browser. The setup costs milliseconds
// and cannot fail for a reason that has nothing to do with this test.
test('an existing order can be cancelled', async ({ page, request }) => {
const created = await request.post('/api/orders', {
data: { sku: 'ESP-01', qty: 1 },
});
await expect(created).toBeOK();
const { id } = await created.json();
await page.goto(`/orders/${id}`);
await page.getByRole('button', { name: 'Cancel order' }).click();
await expect(page.getByText('Order cancelled')).toBeVisible();
});
Asserting that your service returns the shape you expect proves your service agrees with your test. It does not prove it agrees with its consumers, who wrote their own expectations somewhere you cannot see. That is what contract testing is for, and it is a different tool.
Inside the browser test runner
2 entries-
Playwright: API testing
Official docsIssue requests with or without the browser's session, assert on responses, and use HTTP for setup and teardown. Includes the standalone request context, for tests with no page at all.
playwright.dev -
Playwright: network and mocking
Official docsIntercept what the page requests, stub a response, modify one in flight, or record a session and replay it. The reliable way to test the error state your staging backend refuses to produce.
playwright.dev
Dedicated tools
4 entries-
Postman Learning Center
Official docsThe fundamentals, explained clearly: requests, environments, collections, assertions, and running a collection in a pipeline. Even if you end up somewhere else, the vocabulary here is the industry's.
learning.postman.com -
Bruno
ToolAn open-source API client that stores collections as plain files in your repository rather than in a vendor's cloud. Worth knowing about if “our API tests live in someone's personal workspace” is a sentence you have said out loud.
docs.usebruno.com -
REST Assured
ToolThe long-standing Java DSL for HTTP tests, with a given/when/then shape that reads well in a report. Still the default in most JVM shops.
rest-assured.io -
Schemathesis
ToolGenerates test cases from an OpenAPI or GraphQL schema and throws them at your service, including the inputs nobody writes by hand. Property-based testing for APIs, and it finds 500s in almost every service it is pointed at.
schemathesis.readthedocs.io
Contracts and specifications
2 entries-
OpenAPI Specification
StandardThe document your API should already have. Once it exists it stops being documentation and starts being something tools can generate clients, mocks and test cases from.
spec.openapis.org -
Pact: consumer-driven contract testing
Official docsThe consumer records what it actually depends on; the provider proves it still supplies it. The answer to integration-testing a system whose services deploy independently, without standing the whole thing up.
docs.pact.io
What to take away
- Arrange over HTTP, act in the browser.Usually the largest available speed-up, and it removes a whole class of unrelated failures from every test.
- Fast and exact is not the same as sufficient.A green API suite over a broken interface is a real and common outcome.
- Mock the backend you cannot make misbehave.A tested error state beats an untested one, and route interception is not cheating.
Reading is the slow way to learn how a suite behaves. Record one against your own app, free, and watch what the report says.