Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Microsoft Playwright APIRequestContext Fetch

From Leeroopedia
Knowledge Sources
Domains API_Testing, HTTP, REST
Last Updated 2026-02-11 00:00 GMT

Overview

Concrete tool for executing HTTP requests (GET, POST, PUT, DELETE, PATCH, HEAD) against REST APIs with full control over headers, body, and request options, provided by the Playwright library.

Description

The APIRequestContext provides six convenience methods -- get(), post(), put(), delete(), patch(), and head() -- that all delegate to the underlying fetch() method. This design ensures consistent behavior across all HTTP methods while providing ergonomic, method-specific entry points.

The request lifecycle proceeds through two layers:

Client layer (packages/playwright-core/src/client/fetch.ts:L124-170):

  • Each convenience method sets the appropriate HTTP method and calls the internal _innerFetch() method (L172-265).
  • _innerFetch() validates that mutually exclusive body parameters (data, form, multipart) are not combined.
  • It resolves relative URLs against the context's baseURL.
  • It serializes the body according to the parameter used: JSON for data, URL-encoded for form, multipart/form-data for multipart.
  • The serialized request is sent to the server layer via the Playwright protocol channel.

Server layer (packages/playwright-core/src/server/fetch.ts:L146-548):

  • The _sendRequest() method (L285-548) handles the actual HTTP communication using Node.js built-in http/https modules.
  • It follows redirects (HTTP 301, 302, 303, 307, 308) up to the configured maxRedirects limit.
  • It handles HTTP 401 authentication challenges by replaying the request with credentials.
  • It decompresses gzip, br (Brotli), and deflate response bodies.
  • It enforces timeouts and manages connection lifecycle.

Usage

Use these methods whenever you need to make HTTP requests in API tests. Use the specific convenience method matching the desired HTTP verb for clarity, or use fetch() directly when the method needs to be dynamically determined.

Code Reference

Source Location

  • Repository: playwright
  • Client methods: packages/playwright-core/src/client/fetch.ts:L124-170
  • Client _innerFetch: packages/playwright-core/src/client/fetch.ts:L172-265
  • Server _sendRequest: packages/playwright-core/src/server/fetch.ts:L285-548

Signature

// Convenience methods (all delegate to fetch())
request.get(url: string, options?: FetchOptions): Promise<APIResponse>;
request.post(url: string, options?: FetchOptions): Promise<APIResponse>;
request.put(url: string, options?: FetchOptions): Promise<APIResponse>;
request.delete(url: string, options?: FetchOptions): Promise<APIResponse>;
request.patch(url: string, options?: FetchOptions): Promise<APIResponse>;
request.head(url: string, options?: FetchOptions): Promise<APIResponse>;

// Generic fetch method
request.fetch(urlOrRequest: string | Request, options?: FetchOptions): Promise<APIResponse>;

// FetchOptions type
interface FetchOptions {
  params?: { [key: string]: string | number | boolean };
  method?: string;
  headers?: { [key: string]: string };
  data?: string | Buffer | Serializable;
  form?: { [key: string]: string | number | boolean };
  multipart?: {
    [key: string]: string | number | boolean | ReadStream | {
      name: string;
      mimeType: string;
      buffer: Buffer;
    };
  };
  timeout?: number;
  failOnStatusCode?: boolean;
  ignoreHTTPSErrors?: boolean;
  maxRedirects?: number;
  maxRetries?: number;
}

Import

import { test, expect } from '@playwright/test';

I/O Contract

Inputs

Name Type Required Description
url string Yes The target URL. If relative, it is resolved against the context's baseURL. Query parameters can be included directly in the URL or via the params option.
options.params number | boolean } No Query parameters appended to the URL. Values are URL-encoded automatically.
options.method string No HTTP method override. Only used with fetch(); convenience methods set this automatically.
options.headers { [key: string]: string } No Request-specific headers merged with context defaults. Per-request headers take precedence over context headers.
options.data Buffer | Serializable No Request body. Objects are serialized to JSON; strings and Buffers are sent as-is. Mutually exclusive with form and multipart.
options.form number | boolean } No Form-encoded body. Mutually exclusive with data and multipart.
options.multipart object No Multipart form data for file uploads. Mutually exclusive with data and form.
options.timeout number No Request timeout in milliseconds. Defaults to 30000 (30 seconds).
options.failOnStatusCode boolean No If true, throws an error for non-2xx/3xx responses. Defaults to false.
options.ignoreHTTPSErrors boolean No Whether to ignore HTTPS certificate errors for this request. Defaults to the context setting.
options.maxRedirects number No Maximum number of HTTP redirects to follow. Defaults to 20. Set to 0 to not follow redirects.
options.maxRetries number No Maximum number of times to retry the request on transient failures. Defaults to 0.

Outputs

Name Type Description
response Promise<APIResponse> The API response object. Provides status() for the HTTP status code, ok() for a boolean success check (200-299), headers() for response headers, json() for parsed JSON body, text() for string body, and body() for raw Buffer body.

Usage Examples

Basic Example

import { test, expect } from '@playwright/test';

test.use({
  baseURL: 'https://api.example.com',
});

test('CRUD operations on users API', async ({ request }) => {
  // CREATE - POST a new user
  const createResponse = await request.post('/api/users', {
    data: {
      name: 'Alice Johnson',
      email: 'alice@example.com',
    },
  });
  expect(createResponse.ok()).toBeTruthy();
  const created = await createResponse.json();
  const userId = created.id;

  // READ - GET the created user
  const getResponse = await request.get(`/api/users/${userId}`);
  expect(getResponse.ok()).toBeTruthy();
  const user = await getResponse.json();
  expect(user.name).toBe('Alice Johnson');

  // UPDATE - PUT to replace user data
  const putResponse = await request.put(`/api/users/${userId}`, {
    data: {
      name: 'Alice Smith',
      email: 'alice.smith@example.com',
    },
  });
  expect(putResponse.ok()).toBeTruthy();

  // PARTIAL UPDATE - PATCH to update a single field
  const patchResponse = await request.patch(`/api/users/${userId}`, {
    data: { email: 'alice.new@example.com' },
  });
  expect(patchResponse.ok()).toBeTruthy();

  // DELETE - Remove the user
  const deleteResponse = await request.delete(`/api/users/${userId}`);
  expect(deleteResponse.ok()).toBeTruthy();
});

Example: Query Parameters and Custom Headers

import { test, expect } from '@playwright/test';

test('search with query params and pagination', async ({ request }) => {
  const response = await request.get('/api/products', {
    params: {
      search: 'laptop',
      page: 1,
      limit: 20,
      sort: 'price_asc',
    },
    headers: {
      'X-Request-ID': 'test-search-001',
    },
  });
  expect(response.ok()).toBeTruthy();

  const data = await response.json();
  expect(data.results.length).toBeLessThanOrEqual(20);
});

Example: Using fetch() with Dynamic Method

import { test, expect } from '@playwright/test';

test('generic fetch with dynamic method', async ({ request }) => {
  const methods = ['GET', 'HEAD'];

  for (const method of methods) {
    const response = await request.fetch('/api/health', {
      method,
    });
    expect(response.status()).toBe(200);
  }
});

Example: Handling Redirects

import { test, expect } from '@playwright/test';

test('follow redirects up to limit', async ({ request }) => {
  // Follow up to 5 redirects
  const response = await request.get('/api/legacy-endpoint', {
    maxRedirects: 5,
  });
  expect(response.ok()).toBeTruthy();
});

test('do not follow redirects', async ({ request }) => {
  const response = await request.get('/api/redirect-endpoint', {
    maxRedirects: 0,
  });
  expect(response.status()).toBe(301);
});

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment