Q3 of 37 · API testing
What is API testing and how does it differ from UI testing?
Short answer
Short answer: API testing exercises the application's network endpoints directly — sending HTTP/gRPC requests and asserting on responses, without a browser. UI testing drives the rendered application through a real browser. API tests are faster, more deterministic, and run earlier; UI tests catch problems users actually see.
Detail
Both target the same application but at different layers and at different costs.
API testing sends requests to the service over the network protocol — usually HTTP, sometimes gRPC or GraphQL — and asserts on the responses. No browser, no rendering, no JavaScript. Tools include Postman, REST Assured, Playwright's APIRequestContext, supertest (Node), pytest+httpx (Python).
UI testing drives the user-visible interface through a browser. Tools include Selenium, Cypress, Playwright. The browser executes JS, renders DOM, fires events.
The trade-offs:
| API | UI | |
|---|---|---|
| Speed | ms per call | seconds per scenario |
| Determinism | high | lower (animations, timing) |
| Coverage | logic, contracts, data | rendering, accessibility, real flow |
| Cost | cheap | expensive in time and infra |
| Catches | bad data, broken endpoints, schema drift | layout bugs, flow bugs, integration bugs |
The healthy split (test pyramid): most coverage at the API layer, a focused set of UI tests for golden-path user journeys. Don't duplicate — if an API test covers "user can't log in with wrong password," don't also write a UI test for it. Reserve UI for things only the UI can verify (form behaviour, conditional rendering, accessibility).
Junior takeaway: API tests answer "does the service do the right thing?" UI tests answer "do users see the right thing?" Both matter, but API tests are where you should look first when a UI test is slow or flaky — the issue often isn't the UI.
// EXAMPLE
import { test, expect, request } from '@playwright/test';
test('GET /users/:id returns user', async () => {
const ctx = await request.newContext({
baseURL: 'https://api.example.com',
});
const res = await ctx.get('/users/42');
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.id).toBe('42');
expect(body.email).toContain('@');
});