Why API Testing with Playwright?
You already have Playwright for UI — using the same runner for API tests means one report, one CI setup, and easy hybrid tests that seed data via API and verify it in the UI.
The Request Context
ts
import { test, expect, request } from '@playwright/test';
test('list users', async () => {
const api = await request.newContext({ baseURL: 'https://api.example.com' });
const res = await api.get('/users');
expect(res.status()).toBe(200);
});CRUD Example
ts
test('create, update, delete user', async ({ request }) => {
const created = await request.post('/users', { data: { name: 'Ada' } });
const user = await created.json();
const updated = await request.put(`/users/${user.id}`, { data: { name: 'Ada L.' } });
expect(updated.ok()).toBeTruthy();
const deleted = await request.delete(`/users/${user.id}`);
expect(deleted.status()).toBe(204);
});Sharing Auth State with UI
Log in via API, save storage state, then reuse it for every UI test — no more slow UI logins.
ts
// global-setup.ts
const api = await request.newContext();
await api.post('/auth/login', { data: { user: 'admin', pass: '***' } });
await api.storageState({ path: 'state.json' });Assertions on Responses
ts
expect(res.status()).toBe(201);
expect(await res.json()).toMatchObject({ id: expect.any(Number), name: 'Ada' });
expect(res.headers()['content-type']).toContain('application/json');Get Playwright tutorials in your inbox
Weekly tips, real-world examples, and framework patterns – no spam, unsubscribe anytime.