What is API Testing?
API testing verifies that the application's backend services behave correctly without interacting with the user interface.
Instead of clicking buttons and filling forms, API tests communicate directly with REST endpoints, GraphQL services, or microservices using HTTP requests.
Modern applications rely heavily on APIs. Every login request, product search, checkout process, payment transaction, and user profile update usually involves one or more backend APIs.
Testing APIs directly allows automation engineers to validate business logic much earlier, faster, and more reliably than UI automation alone.
For enterprise software, API testing is an essential part of the CI/CD pipeline because backend services can be verified independently of the frontend.
Why Use Playwright for API Testing?
Although Playwright is widely known for browser automation, it also includes a powerful API testing library.
Instead of using multiple tools for UI and API automation, teams can build both types of tests using one framework.
- One language (TypeScript or JavaScript)
- One reporting system
- Shared configuration
- Shared authentication
- Hybrid UI + API testing
- Faster execution
- Easier maintenance
Many organizations are replacing separate API tools for simple and medium-complexity REST API testing with Playwright because it reduces framework complexity.
REST API Basics
REST APIs typically use standard HTTP methods.
- GET — Retrieve data
- POST — Create data
- PUT — Replace existing data
- PATCH — Update part of an existing resource
- DELETE — Remove data
Every API request usually contains a URL, HTTP method, headers, optional request body, and optional query parameters. The server returns a status code, headers, and a JSON body.
Understanding these fundamentals is critical before writing Playwright API tests.
Understanding APIRequestContext
Playwright exposes APIRequestContext as its built-in HTTP client. It is available automatically as the request fixture inside every test, or it can be created manually with playwright.request.newContext().
APIRequestContext supports base URLs, default headers, cookies, storage state reuse, HTTPS configuration, and multipart file uploads — everything needed for enterprise API automation.
Each request context is isolated by default, which prevents cookies and authentication from leaking between tests unless you explicitly share storageState.
Creating Your First API Test
Playwright provides the request fixture for API testing.
import { test, expect } from '@playwright/test';
test('Get all users', async ({ request }) => {
const response = await request.get('/users');
expect(response.ok()).toBeTruthy();
});This simple test sends a GET request and verifies that the server responds successfully.
GET Requests
GET requests retrieve data from the server.
const response = await request.get('/products');
expect(response.status()).toBe(200);
const products = await response.json();
expect(products.length).toBeGreaterThan(0);Always validate the status code, response body, and business data.
POST Requests
POST creates new resources.
const response = await request.post('/users', {
data: {
firstName: 'John',
lastName: 'Doe',
email: 'john@test.com'
}
});
expect(response.status()).toBe(201);
const createdUser = await response.json();After creation, verify the returned object and persist any identifiers needed for later steps.
PUT Requests
PUT replaces an existing resource.
await request.put('/users/10', {
data: {
firstName: 'Updated',
lastName: 'User'
}
});PATCH Requests
PATCH modifies only specific fields.
await request.patch('/users/10', {
data: {
firstName: 'Michael'
}
});PATCH is preferred when updating partial resources because it reduces payload size and avoids accidental overwrites.
DELETE Requests
const response = await request.delete('/users/10');
expect(response.status()).toBe(204);
// Verify the resource no longer exists
const getResponse = await request.get('/users/10');
expect(getResponse.status()).toBe(404);After deletion, verify that the resource no longer exists by attempting to retrieve it.
Sending Headers
Many APIs require custom headers.
await request.get('/orders', {
headers: {
Authorization: 'Bearer token',
Accept: 'application/json'
}
});Authentication
Enterprise APIs usually require authentication.
const loginResponse = await request.post('/login', {
data: {
username: 'admin',
password: 'password'
}
});
const { accessToken } = await loginResponse.json();
const usersResponse = await request.get('/users', {
headers: {
Authorization: `Bearer ${accessToken}`
}
});Capture the returned access token and include it in future requests. For reusable sessions, store the authentication state with storageState().
Query Parameters
await request.get('/products', {
params: {
category: 'books',
limit: 10
}
});Validating Responses
Never validate only the status code. Validate business data.
const response = await request.get('/users/1');
const user = await response.json();
expect(user.firstName).toBe('John');
expect(user.email).toContain('@');
expect(user.id).toBeGreaterThan(0);JSON Schema Validation
Large projects often validate API responses against JSON schemas to ensure contract consistency.
- Strong validation
- Easier maintenance
- Contract testing
- Reduced production defects
import { z } from 'zod';
const userSchema = z.object({
id: z.number(),
firstName: z.string(),
lastName: z.string(),
email: z.string().email()
});
const user = await response.json();
userSchema.parse(user);Schema validation catches unexpected field changes early and documents the API contract directly inside the test suite.
File Upload APIs
Many enterprise systems upload files using APIs.
import * as fs from 'fs';
const response = await request.post('/upload', {
multipart: {
file: {
name: 'resume.pdf',
mimeType: 'application/pdf',
buffer: fs.readFileSync('resume.pdf')
}
}
});
expect(response.status()).toBe(200);API Chaining
Real-world workflows often depend on previous API responses.
- Create User
- Extract User ID
- Update User
- Retrieve User
- Delete User
const created = await request.post('/users', {
data: { firstName: 'Alice', lastName: 'Smith' }
});
const { id } = await created.json();
await request.put(`/users/${id}`, {
data: { firstName: 'Alice', lastName: 'Johnson' }
});
await request.delete(`/users/${id}`);This technique is known as API chaining and is frequently used in automation frameworks to model end-to-end business flows.
API + UI Hybrid Testing
One of Playwright's greatest strengths is combining API and UI automation.
test('customer appears in dashboard after API creation', async ({ page, request }) => {
// Create a customer using the API
const response = await request.post('/customers', {
data: { name: 'Acme Corp', email: 'acme@example.com' }
});
const customer = await response.json();
// Open the web application and verify the customer
await page.goto('/dashboard');
await page.getByPlaceholder('Search customers').fill(customer.name);
await expect(page.getByRole('row', { name: customer.name })).toBeVisible();
});Hybrid testing dramatically reduces test execution time by preparing data through APIs instead of navigating the UI.
Enterprise API Framework Design
A scalable framework may look like this:
src/
api/
clients/
services/
models/
fixtures/
utils/
config/
tests/api/
tests/ui/Typical service classes include UserService, ProductService, OrderService, and AuthenticationService. This architecture keeps business logic separate from test cases.
export class UserService {
constructor(private request: APIRequestContext) {}
async createUser(data: CreateUserRequest) {
const response = await this.request.post('/users', { data });
expect(response.status()).toBe(201);
return response.json();
}
async getUser(id: number) {
return this.request.get(`/users/${id}`);
}
async deleteUser(id: number) {
return this.request.delete(`/users/${id}`);
}
}Service classes centralize endpoint knowledge, making tests cleaner and API changes easier to maintain.
Best Practices
- Create reusable API service classes.
- Separate test data from test logic.
- Validate business rules, not just status codes.
- Use environment configuration for base URLs and credentials.
- Store authentication tokens securely.
- Reuse API clients across related tests.
- Keep tests independent and idempotent.
Common Mistakes
- Hardcoding URLs inside test files.
- Ignoring response body validation.
- Repeating authentication logic in every test.
- Using the UI to prepare test data.
- Sharing mutable test data across tests.
- Calling response.json() more than once.
- Forgetting to dispose manually created request contexts.
Interview Questions
What is API testing?
API testing verifies backend functionality without interacting with the user interface.
Why use Playwright for API testing?
Because it combines UI and API automation in one framework, reducing maintenance and improving efficiency.
What is API chaining?
Using the output of one API request as the input for another request.
Why combine UI and API tests?
API calls prepare test data much faster than performing the same actions through the UI, resulting in faster and more stable end-to-end tests.
Summary
Playwright is much more than a browser automation framework. Its built-in API testing capabilities allow engineers to build scalable, maintainable, and efficient automation solutions using a single technology stack.
By mastering REST APIs, authentication, request contexts, response validation, and hybrid UI/API workflows, SDETs can create enterprise-grade frameworks that support modern software delivery pipelines.
Get Playwright tutorials in your inbox
Weekly tips, real-world examples, and framework patterns – no spam, unsubscribe anytime.
Playwright Framework Series
View all →- 1Getting Started with Playwright: Installation, Setup, and Your First Test
- 2Playwright Locators: The Complete Guide with Real-World Examples
- 3Playwright Actions: Complete Guide to Click, Fill, Hover, Keyboard, Mouse & File Upload
- 4Playwright Assertions: The Complete Guide with Real-World Examples
- 5Playwright Auto Waiting: The Complete Guide with Real-World Examples
- 6Playwright Fixtures: The Complete Guide with Real-World Examples
- 7Playwright Browser Context & Multiple Tabs: The Complete Guide with Real-World Examples
- 8Playwright Authentication & Session Management: Complete Guide with Enterprise Examples
- 9Playwright Network Interception & API Mocking: Complete Guide with Real-World Examples
- 10Playwright Page Object Model (POM): The Complete Guide with Enterprise Examples
- 11Page Object Model with Playwright: A Practical Guide
- 12How to Build a Robust Professional Playwright Framework from Scratch (Step-by-Step)
- 13Building an Enterprise Playwright Framework from Scratch
API Testing Series
View all →- 1Playwright API Testing: The Complete Guide with Real-World Examples
- 2Part 1 : Playwright API Testing Tutorial: Build Enterprise-Level API Automation Framework
- 3Part 2: Playwright API Testing Tutorial: Setting Up Project & Sending Your First API Request
- 4Part 3: Mastering CRUD Operations in Playwright API Testing
- 5Part 4: Authentication in Playwright API Testing (Bearer Token, JWT, API Key & Reusable Fixtures)
- 6Part 5: Building an Enterprise-Level Playwright API Automation Framework
- 7Part 6: API Models, Schema Validation & Test Data Management in Playwright
- 8Part 7: Custom Fixtures, Hooks, Logging & Parallel Execution in Playwright API Testing
- 9Part 8: Building a Production-Ready Playwright API Framework (Environment Management, CI/CD, Reporting & Best Practices)
- 10Part 9: Advanced Playwright API Testing Techniques for Enterprise Automation
- 11Part 10: Building a Complete Enterprise Playwright API Automation Framework (Final Part)
- 12API Testing with Playwright: Request Context, Auth, and Assertions