Q3 of 37 · API testing

What is API testing and how does it differ from UI testing?

API testingJuniorapiui-testingtest-pyramidfundamentals

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('@');
});

// WHAT INTERVIEWERS LOOK FOR

Distinguishing layer (network vs browser), the pyramid argument (lots of API, few UI), and the discipline to not duplicate logic across layers.

// COMMON PITFALL

Treating API and UI tests as redundant ('we have API tests, do we need UI tests?'). They cover different failure modes; the question is the *split*, not 'one or the other.'