API Testing
How do I write API tests that capture request and response analytics with TestRelic, using the request fixture — no browser required?
API testing with TestRelic captures analytics about HTTP requests, responses, timing, and test results through the request fixture, without launching a browser.
No browser required
API tests run without launching a browser, making them faster and more lightweight than E2E tests.
Setting up the API fixture
Extend the base Playwright fixture with testRelicApiFixture in your test files:
import { test as base } from '@playwright/test';
import { testRelicApiFixture } from '@testrelic/playwright-analytics/api-fixture';
import { expect } from '@testrelic/playwright-analytics/fixture';
const test = base.extend(testRelicApiFixture);
test('fetch posts', { tag: ['@api'] }, async ({ request }) => {
const response = await request.get('https://jsonplaceholder.typicode.com/posts');
expect(response.status()).toBe(200);
const posts = await response.json();
expect(posts).toBeInstanceOf(Array);
});Import expect from TestRelic (either .../api-fixture or .../fixture) so assertions are captured — it behaves exactly like Playwright's expect.
When a run opens the API workspace
A run is routed to the API workspace when every test in it is an API test — tagged @api, under an api/ path, in a dedicated API project, or using the API request fixture. Mixed UI + API runs are not reclassified. Request and response cookies are captured with their values masked, shown in the API Cookies tab.
CRUD patterns
import { test as base } from '@playwright/test';
import { testRelicApiFixture } from '@testrelic/playwright-analytics/api-fixture';
import { expect } from '@testrelic/playwright-analytics/fixture';
const test = base.extend(testRelicApiFixture);
const BASE_URL = 'https://jsonplaceholder.typicode.com';
test('complete CRUD workflow', { tag: ['@api', '@crud'] }, async ({ request }) => {
const createRes = await request.post(`${BASE_URL}/posts`, {
data: { title: 'Test', body: 'Content', userId: 1 },
});
expect(createRes.status()).toBe(201);
const post = await createRes.json();
const readRes = await request.get(`${BASE_URL}/posts/${post.id}`);
expect(readRes.status()).toBe(200);
const updateRes = await request.put(`${BASE_URL}/posts/${post.id}`, {
data: { ...post, title: 'Updated' },
});
expect(updateRes.status()).toBe(200);
const deleteRes = await request.delete(`${BASE_URL}/posts/${post.id}`);
expect(deleteRes.status()).toBe(200);
});Chaining API calls
test('API chaining - user and posts', { tag: ['@api', '@chain'] }, async ({ request }) => {
const userResponse = await request.get('https://jsonplaceholder.typicode.com/users/1');
const user = await userResponse.json();
const postsResponse = await request.get('https://jsonplaceholder.typicode.com/posts', {
params: { userId: user.id },
});
const posts = await postsResponse.json();
expect(posts.every((post) => post.userId === user.id)).toBe(true);
});Authentication
test('bearer token authentication', { tag: ['@api', '@auth'] }, async ({ request }) => {
const response = await request.get('https://api.example.com/protected', {
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
});
expect(response.status()).toBe(200);
});Sensitive data
Always use environment variables for API keys, tokens, and passwords. Configure redactPatterns (see Configuration) so sensitive values never appear in reports.
Configuration for API-only reporters
export default defineConfig({
reporter: [
['@testrelic/playwright-analytics', {
outputPath: './test-results/api-analytics.json',
includeStackTrace: true,
includeCodeSnippets: true,
redactPatterns: [/api_key=[^&\s]+/gi, /password=[^&\s]+/gi],
}],
],
});Running API tests
npx playwright test --grep @api
npx playwright test tests/api/posts.spec.tsBest practices
- Keep credentials in environment variables, never hardcoded.
- Validate response shape, not just status code.
- Test error paths (404s, timeouts) as well as happy paths.
- Clean up created test data in a
finallyblock.