Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Build a custom API testing framework by keeping Playwright Test as the runner and adding a thin, typed layer around APIRequestContext. Put the base URL, headers, authentication, timeout policy, proxy settings, and environment selection in configuration; wrap endpoints in domain clients; generate deterministic test data; and use fixtures to manage request-context lifecycles and cleanup. Tests should then describe business behavior rather than repeat URL construction or authentication code. The same framework can call APIs directly, create server state before a browser test, and verify server-side results after a UI action.

What is a custom API testing framework with Playwright and TypeScript?

It is a small application-specific layer built on Playwright Test and its APIRequestContext HTTP client. Playwright supplies the test runner, fixtures, assertions, request handling, and browser integration; your framework supplies the conventions that make your API understandable and repeatable: configuration, endpoint methods, data builders, authentication, assertions, and cleanup.

This approach is deliberately thin. You are not hiding every HTTP detail behind a generic abstraction. Instead, you centralize the details that change frequently and expose domain operations such as orders.create(), users.getById(), or projects.delete(). A test can therefore state the behavior it is checking while still retaining useful response and request diagnostics.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Microsoft’s APIRequestContext reference describes the API as being used for Web API testing. The official API-testing guidance identifies three practical roles: test the server API directly, prepare server-side state before opening the web application, and validate server-side postconditions after browser actions.

#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter | 4Pack Type C Female to A Male Cable Converter for Apple Duo 17 16 15 14 Plus,iWatch Watch 12 11 10,iPad 9 8 Air,Airpods 5 4
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

How should the framework be organized?

Use layers with clear ownership. Configuration decides how requests are sent, endpoint clients decide which operations exist, builders decide what data is generated, fixtures decide when resources are created and disposed, and tests decide which business rules matter.

Recommended project layout

tests/
  api/
    users.spec.ts
    orders.spec.ts
  ui/
    order-flow.spec.ts
framework/
  clients/
    users.client.ts
    orders.client.ts
  builders/
    user.builder.ts
    order.builder.ts
  fixtures/
    api.fixtures.ts
  assertions/
    response.assertions.ts
  config/
    environment.ts
playwright.config.ts
  • Configuration: base URL, common headers, authentication, proxy, timeout, and environment selection.
  • Endpoint clients: typed methods for get, post, put, patch, and delete.
  • Builders: deterministic payloads with explicit overrides for the test under execution.
  • Fixtures: request contexts, authenticated clients, created entities, and teardown.
  • Assertion helpers: consistent status and body mismatch messages.
  • Tests: business behavior, permissions, validation, and integration flows.

Keep URL construction and repeated headers in the client layer. Keep expected business values in the test or a domain-specific assertion helper. This prevents a test from passing simply because it repeats the same implementation detail that it should be checking.

How do I configure Playwright for API requests?

Set the API’s baseURL and common extraHTTPHeaders once in playwright.config.ts. The official example supplies an authorization token from an environment variable and sends an Accept header. Configuration is also the right place to select an environment and establish a timeout policy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    baseURL: process.env.API_BASE_URL,
    extraHTTPHeaders: {
      Accept: 'application/json',
      Authorization: `Bearer ${process.env.API_TOKEN ?? ''}`,
    },
  },
});

Do not silently run against a default environment when a required value is absent. A configuration module can validate the environment name and token before tests start, then expose typed settings to fixtures and clients. Keep secrets in environment variables or the CI secret store rather than in source files.

The configured values apply to the Playwright request fixture. A client method should normally pass a relative path and operation-specific data, allowing one configuration change to move the suite between environments without editing every test.

Which APIRequestContext should each test use?

Use Playwright Test’s built-in request fixture for ordinary tests. Create a standalone context with playwright.request.newContext() only when a suite needs explicit lifecycle control or a deliberately separate cookie store.

Choice Cookie behavior Lifecycle Best fit
Test request fixture Managed by the test fixture; use it for the test’s normal API calls. Playwright manages setup and teardown. Most isolated API tests and fixture-based clients.
Standalone request.newContext() Isolated cookie storage unless you deliberately connect it to another context. You must dispose it when the suite finishes. Custom suites, multiple identities, or explicit lifecycle control.
Context associated with a browser context Shares cookies with that browser context. Follows the browser context’s lifecycle. End-to-end flows that intentionally move authenticated state between API and UI.

Sharing cookies is convenient for a single end-to-end flow, but it couples the API and browser portions of the test. Per-test or per-context isolation reduces cross-test coupling and makes failures easier to reproduce. Choose deliberately instead of allowing cookie behavior to be an accidental side effect.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter | USB C Dongle with 90W Max Power Delivery, 3×5Gbps USB A Data Ports, for MacBook, Dell, and More (Charger Not Included)
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

How do I build typed endpoint clients?

Give each domain a small client with methods that accept typed input and return a response or a typed result. The client owns paths, query parameters, request encoding, and operation-specific headers.

import type { APIRequestContext, APIResponse } from '@playwright/test';

type CreateUser = { email: string; displayName: string };
type User = { id: string; email: string; displayName: string };

export class UsersClient {
  constructor(private readonly request: APIRequestContext) {}

  async create(data: CreateUser): Promise<APIResponse> {
    return this.request.post('/users', { data });
  }

  async get(id: string): Promise<APIResponse> {
    return this.request.get(`/users/${encodeURIComponent(id)}`);
  }

  async search(status: string): Promise<APIResponse> {
    return this.request.get('/users', { params: { status } });
  }

  async remove(id: string): Promise<APIResponse> {
    return this.request.delete(`/users/${encodeURIComponent(id)}`);
  }
}

Use data for JSON objects, params for query strings, form for URL-encoded form submissions, and multipart for uploads or multipart fields. Keeping these choices in the client prevents individual tests from constructing subtly different requests for the same operation.

Whether a method returns APIResponse or parses JSON into a domain type is a design decision. Returning the response makes status, headers, and raw-body diagnostics available to the test. Parsing in a dedicated method can make successful-path tests concise. In either case, preserve enough information to explain a failure.

How should authentication and state be handled?

For a token or header that applies to the whole suite, configure it once with extraHTTPHeaders. This avoids copying authorization code into every endpoint method. For cookie-based authentication or state that must move between an API context and a browser context, use storageState().

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Create an API request context for authentication.
  2. Sign in through the API and obtain the resulting authenticated state.
  3. Save that state with storageState().
  4. Create a browser context using the saved state.
  5. Run the UI test with the same authenticated cookies or token state.

Decide whether that state is shared for an end-to-end scenario or regenerated for each test. Shared state shortens setup but increases coupling; isolated state costs more setup while limiting interference between tests. The framework should make the choice visible in its fixtures rather than relying on a hidden global context.

How do fixtures manage contexts, test data, and cleanup?

Fixtures are the seam between Playwright’s lifecycle and your domain objects. A fixture can expose an authenticated request client, create an entity before a test, return its ID, and remove it after the test. For suite-wide data, use beforeAll or a worker-scoped fixture only when the data is safe to share.

import { test as base } from '@playwright/test';
import { UsersClient } from '../clients/users.client';

export const test = base.extend<{ users: UsersClient }>({
  users: async ({ request }, use) => {
    const users = new UsersClient(request);
    await use(users);
  },
});

When a fixture creates records, track every created ID immediately. Teardown should attempt deletion or reset even when assertions fail. If the service supports idempotent cleanup, use it; otherwise, make the cleanup path tolerate an already-removed record and report genuine failures separately from the original test failure.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter | 85W Max PD, 2 USB 3.0 & 1 USBC Data Ports, SD/TF Card Reader, for Laptops/Mac and Other Type C Devices (Charger Not Included)
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Manually created contexts have a stricter obligation: call their disposal method when the suite ends. Leaking contexts can leave cookies, sockets, or server-side data behind and can make later tests appear flaky.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How should test data be generated?

Use builders that produce valid, deterministic payloads and accept overrides. A builder should make uniqueness explicit, not hide it in a random value that a failure cannot reproduce.

export function userPayload(overrides: Partial<CreateUser> = {}): CreateUser {
  return {
    email: `api-test-${process.env.TEST_RUN_ID ?? 'local'}@example.test`,
    displayName: 'API test user',
    ...overrides,
  };
}

Include a run identifier or another controlled uniqueness value when the API rejects duplicate records. Pass the resulting ID between setup, assertions, and teardown instead of searching by a mutable display name. If a test is retried, deterministic naming and explicit cleanup reduce the chance that the retry creates an unnoticed duplicate.

What should API tests assert?

Assert both the HTTP result and the part of the response that proves the business rule. A status-only check can pass while the server returns the wrong object; a full-body equality check can fail for irrelevant timestamps or ordering differences.

  • Check response.ok() or the exact expected status for the operation.
  • Parse the JSON body only after confirming the response is in the expected class of result.
  • Assert required identifiers, state transitions, permissions, and validation messages.
  • Include the response status and body in assertion failures so a server error is diagnosable from the test output.
  • Use focused field assertions for values that are contractually important, rather than comparing incidental fields.
const response = await users.create(userPayload());
expect(response.status()).toBe(201);
const body = await response.json();
expect(body).toMatchObject({
  email: expectedEmail,
  displayName: 'API test user',
});
expect(body.id).toEqual(expect.any(String));

Put recurring checks in assertion helpers, but keep the expected rule visible at the call site. For example, a helper can format a status-and-body mismatch while the test still states that a newly created user must have an ID and the submitted email.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do retries, timeouts, and eventual consistency work?

The APIRequestContext reference documents a default request timeout of 30,000 milliseconds. It also documents a default maximum of 20 redirects and a maxRetries option that retries network errors; the current implementation specifically retries ECONNRESET, not HTTP response codes.

Failure type What the built-in policy does What your framework should do
Network reset such as ECONNRESET maxRetries can retry it. Keep the limit bounded and ensure the operation is safe to repeat.
HTTP 429 or 5xx response Not retried by that transport option. Add an explicit, domain-aware retry or polling policy only where the operation permits it.
Slow but valid response Subject to the request timeout. Set a justified timeout policy and report which operation exceeded it.
Redirect chain Reference behavior allows up to 20 redirects by default. Investigate unexpected redirects instead of masking them with a larger limit.

Keep transport retries separate from application retries. A network retry may be safe for a read but dangerous for a non-idempotent create if the server accepted the first request before the connection failed. For eventual consistency, poll a read endpoint with a bounded interval and an explicit terminal condition rather than blindly repeating the write.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray | Data transfer & Fast charging for MacBook, iPhone 17/16/15, iPad, Samsung Galaxy, Apple Watch
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

How can API tests prepare and verify browser tests?

Use the API to establish expensive or awkward preconditions, then let the browser test focus on the user journey. After the UI action, call the API to verify the server-side postcondition that the screen alone may not expose reliably.

  1. Use an API fixture to create the minimum records the UI scenario needs.
  2. Pass stable IDs or a unique business key into the browser test.
  3. Open the application and perform the user action.
  4. Use the API client to fetch the resulting server record.
  5. Assert the persisted status, ownership, totals, or other business fields.
  6. Delete or reset the records in teardown.

For authentication shared between the two sides, save API-created state with storageState() and construct the browser context from it. If the flow is intended to test login itself, do not bypass that screen; use a separate fixture or project for the authenticated scenario.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which design choices reduce flakiness?

Most API-suite instability comes from hidden state, duplicate data, or assertions that are weaker or broader than the contract. Make those choices explicit.

  • Give every test an isolated request context unless shared cookies are part of the scenario.
  • Generate unique, traceable records and delete them in teardown.
  • Use fixture scope intentionally: test scope for isolation, suite scope only for safe shared data.
  • Separate network retries from retries for throttling, server errors, and eventual consistency.
  • Assert business fields and preserve response bodies in failure messages.
  • Keep endpoint paths and headers in one client instead of duplicating them in tests.
  • Dispose every manually created request context.

These conventions also make parallel execution safer because tests do not depend on another test’s cookies, IDs, or cleanup order.

What is a practical build sequence?

Build the smallest vertical slice first, then add domains and integration behavior as the conventions prove useful.

  1. Choose environment inputs: define the base URL, token source, headers, timeout policy, and proxy settings.
  2. Configure Playwright: set baseURL and extraHTTPHeaders in the Playwright configuration.
  3. Implement one client: wrap one read and one write operation with typed inputs.
  4. Add a builder: create deterministic valid data with override support.
  5. Add assertions: check status and the fields that represent the business contract.
  6. Promote setup to a fixture: expose the client, created IDs, and teardown through Playwright fixtures.
  7. Add authentication state: use headers for token-based calls or storageState() when API and browser cookies must be reused.
  8. Set reliability rules: define bounded transport retries, application retries, polling, and cleanup behavior.
  9. Connect UI and API: prepare state before browser actions and verify persisted state afterward.

At each step, keep a failing test’s output useful: include the operation name, status, response body, and entity identifier. A framework is successful when adding a new endpoint requires mostly a client method and a focused test, not another custom setup pattern.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What are the trade-offs of this approach?

Decision Advantage Cost or risk
Thin domain clients Readable tests and centralized paths. Each new domain needs a client and types.
Fixture-managed contexts Predictable setup and teardown. Fixture scope mistakes can create shared state.
Standalone contexts Strong isolation and explicit lifecycle. You must dispose them and manage authentication.
API setup for UI tests Fast, precise preconditions. Can bypass UI behavior that deserves its own test.
Contract-level assertions Catches incorrect bodies that status checks miss. Requires maintaining the fields that truly matter.
Transport retries Recovers from selected network failures. Can duplicate unsafe writes if idempotency is ignored.

The framework should not make every test end-to-end. Use direct API tests for server rules, API setup where the browser is not the subject of the test, and combined API/UI flows where the boundary between persisted state and user-visible behavior is important.

Best Value
Sale
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display | 85W Max PD, 1 Powered USB-C 5Gbps & 2 Powered USB-A 3.0 5Gbps Data Ports, for MacBook Pro, MacBook Air, Dell and More (Black)
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

What should you avoid when building the framework?

  • A universal request wrapper: a generic method that accepts arbitrary URLs and options often hides domain intent and weakens typing.
  • Status-only testing: a 200 or 201 does not prove that the correct resource was returned.
  • Unbounded retries: they turn a real outage into a long timeout and can create duplicate data.
  • Global mutable clients: shared cookies and IDs let one test contaminate another.
  • UI-only verification: a rendered label may not prove that the server persisted the expected state.
  • Forgotten teardown: leftover records can alter validation, uniqueness, and authorization outcomes in later runs.

Start with explicit code and refactor only repeated behavior. The goal is a framework that makes correct tests easy, not an abstraction so large that diagnosing an HTTP failure requires reading several layers first.

How do I know the framework is ready for more endpoints?

Add another domain when the existing pattern can answer these questions without a new convention: where configuration lives, how authentication is applied, how data is made unique, how a response is asserted, and how records are cleaned up. If each answer differs by endpoint, standardize the lifecycle before adding more clients.

A mature suite will have a small number of reliable fixtures, typed domain methods, builders with controlled overrides, and assertion helpers that preserve diagnostic detail. It will also make the choice between shared and isolated state visible. That combination gives Playwright’s API client a stable role in direct API tests and browser-integrated scenarios without turning the test code into a second application.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can APIRequestContext test a service without opening a browser?

Yes. A test can use the Playwright request fixture or a standalone request context to send HTTP calls directly to the service. Browser automation is only needed when the scenario includes browser behavior.

Does maxRetries retry a 500 or 429 response automatically?

No. The documented transport option targets network errors, with the current implementation specifically retrying ECONNRESET. Handle HTTP response retries or polling as an explicit application policy with bounded attempts.

When should I create a standalone request context instead of using request?

Create one when you need a separately controlled lifecycle, multiple independent identities, or cookie storage that must not mix with the test fixture. Dispose it explicitly when the suite is finished.

Can the same authenticated state be reused by API and browser tests?

Yes, when the state is represented by cookies or compatible token state. Authenticate through an API context, save it with storageState(), and create the browser context from that saved state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What is the documented default API request timeout?

The APIRequestContext reference documents a default timeout of 30,000 milliseconds. Treat that as a Playwright API-reference setting that may change in a future release, and set a deliberate policy for operations with different response characteristics.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.