Playwright API Testing

API Testing with Playwright Using Java

From REST APIs to API + UI Automation

When most testers hear Playwright, the first thing that comes to mind is browser automation.But Playwright is not limited to browser automation. It also provides an API testing capability that allows you to send HTTP requests directly to your application’s backend without opening a browser. And this becomes particularly interesting when you are already using Playwright with Java for UI automation. Instead of maintaining one framework for UI testing and another framework for API testing, you can use Playwright to handle both.

With Playwright’s APIRequestContext, you can:

  • Send REST API requests
  • Validate HTTP status codes
  • Validate response headers and bodies
  • Send request payloads
  • Handle authentication
  • Create test data through APIs
  • Prepare backend state before UI tests
  • Validate backend state after UI actions
  • Combine API and UI automation in the same test

This makes Playwright a powerful option for building full-stack automated tests.

In this article, we will explore API Testing with Playwright using Java with practical examples.


What Is API Testing with Playwright?

Playwright provides the APIRequestContext API for sending HTTP requests directly to an application.

You can create an isolated API request context using:

APIRequestContext request = playwright.request().newContext();

From there, you can perform operations such as:

GET
POST
PUT
PATCH
DELETE

Playwright’s Java API provides corresponding methods such as get(), post(), put(), patch(), and delete().

The important point is that you don’t need a browser to perform these API calls.

For example:

APIResponse response = request.get("/users");

The response can then be inspected and validated.


Setting Up Playwright API Testing with Java

Let’s assume we are using:

  • Java
  • Maven
  • Playwright
  • JUnit 5

Add Playwright to your Maven project.

<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>YOUR_PLAYWRIGHT_VERSION</version>
</dependency>

You can use the current Playwright Java version appropriate for your project rather than hardcoding an outdated version into your framework.

Playwright’s official Java API supports creating an APIRequestContext through Playwright.request().newContext().


Creating an APIRequestContext

A basic API test setup looks like this:

import com.microsoft.playwright.APIRequest;
import com.microsoft.playwright.APIRequestContext;
import com.microsoft.playwright.APIResponse;
import com.microsoft.playwright.Playwright;
public class ApiTest {
private Playwright playwright;
private APIRequestContext request;
public void setUp() {
playwright = Playwright.create();
request = playwright.request().newContext(
new APIRequest.NewContextOptions()
.setBaseURL("https://api.example.com")
);
}
public void tearDown() {
request.dispose();
playwright.close();
}
}

Using setBaseURL() is useful because you don’t need to repeatedly specify the complete URL.

Instead of:

request.get("https://api.example.com/users");

you can write:

request.get("/users");

Playwright resolves the relative URL against the configured base URL.


GET Request with Playwright

Let’s start with a simple GET request.

@Test
void getUsers() {
APIResponse response = request.get("/users");
System.out.println(response.status());
System.out.println(response.text());
}

The APIResponse object provides access to information such as:

  • Status code
  • Response body
  • Headers
  • Status text

For example:

System.out.println(response.status());
System.out.println(response.statusText());
System.out.println(response.text());

Playwright’s APIResponse represents responses returned from APIRequestContext methods such as get() and post().


Validating the HTTP Status Code

Sending an API request is only half the job.

The real value of API testing comes from validating the response.

Using JUnit 5:

import static org.junit.jupiter.api.Assertions.assertEquals;
@Test
void shouldReturnUsers() {
APIResponse response = request.get("/users");
assertEquals(200, response.status());
}

This verifies that the API returned HTTP 200 OK.

You can also validate other expected responses:

assertEquals(201, response.status());

for resource creation,

or:

assertEquals(401, response.status());

for an authentication failure scenario.


Validating the Response Body

The response body can be retrieved using:

String responseBody = response.text();
System.out.println(responseBody);

Suppose the API returns:

{
"id": 101,
"name": "John",
"email": "john@example.com"
}

You could perform a basic validation:

assertTrue(response.text().contains("John"));

However, string-based validation can become fragile.

For real-world automation frameworks, it is better to parse JSON and validate specific fields.

For example, using Jackson:

ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonResponse =
objectMapper.readTree(response.text());
assertEquals("John", jsonResponse.get("name").asText());
assertEquals("john@example.com",
jsonResponse.get("email").asText());

This approach allows you to validate individual JSON properties instead of searching the entire response as a string.


Validating Response Headers

API testing isn’t only about the response body.

Headers are equally important.

For example:

Map<String, String> headers = response.headers();
System.out.println(headers);

You can validate a particular header:

assertEquals(
"application/json",
response.headers().get("content-type")
);

Depending on the API and framework requirements, you might also validate:

  • Content-Type
  • Cache-Control
  • Location
  • Security headers
  • Correlation IDs
  • Custom application headers

Playwright’s APIResponse.headers() provides the response headers as a map.


POST Request with Playwright

Now let’s create a resource using a POST request.

Suppose our API expects:

{
"name": "John Doe",
"email": "john@example.com"
}

We can create the request body using a Java Map.

Map<String, Object> requestBody = new HashMap<>();
requestBody.put("name", "John Doe");
requestBody.put("email", "john@example.com");

Then send the request:

APIResponse response = request.post(
"/users",
RequestOptions.create()
.setData(requestBody)
);

Playwright’s Java API supports passing JSON-compatible data through RequestOptions.setData().

Now validate the response:

assertEquals(201, response.status());

And inspect the returned user:

System.out.println(response.text());

Using POJOs for API Request Bodies

For a larger automation framework, creating request bodies with Map<String, Object> everywhere can become difficult to maintain.

A better approach is to create Java POJOs.

For example:

public class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}

Then serialize the object using Jackson:

ObjectMapper objectMapper = new ObjectMapper();
User user = new User(
"John Doe",
"john@example.com"
);
String requestBody =
objectMapper.writeValueAsString(user);

Then send it:

APIResponse response = request.post(
"/users",
RequestOptions.create()
.setHeader("Content-Type", "application/json")
.setData(requestBody)
);

This approach scales much better when request models become complex.


API Authentication with Playwright

Authentication is one of the most important parts of API testing.

Imagine an API requiring:

Authorization: Bearer <token>

We can configure the authorization header when creating the API request context.

Map<String, String> headers = new HashMap<>();
headers.put(
"Authorization",
"Bearer " + token
);
headers.put(
"Content-Type",
"application/json"
);

Then:

request = playwright.request().newContext(
new APIRequest.NewContextOptions()
.setBaseURL("https://api.example.com")
.setExtraHTTPHeaders(headers)
);

Now every request made using this context can use the configured headers.

Playwright’s official API testing documentation demonstrates configuring authorization headers on an APIRequestContext.


Testing Authentication APIs

You can also test the authentication endpoint itself.

For example:

Map<String, Object> loginRequest = new HashMap<>();
loginRequest.put("username", "testuser");
loginRequest.put("password", "password123");

Send the request:

APIResponse response = request.post(
"/login",
RequestOptions.create()
.setData(loginRequest)
);

Validate:

assertEquals(200, response.status());

Then extract the token:

JsonNode jsonResponse =
objectMapper.readTree(response.text());
String token =
jsonResponse.get("token").asText();

That token can then be used for subsequent API calls.

This creates a simple API authentication flow:

Login API
Extract Token
Create Authenticated API Context
Call Protected API
Validate Response

Negative API Testing

A good API test suite should not only test successful scenarios.

Negative scenarios are equally important.

For example:

Invalid authentication

assertEquals(401, response.status());

Invalid request data

assertEquals(400, response.status());

Resource not found

assertEquals(404, response.status());

Forbidden operation

assertEquals(403, response.status());

You can also validate the error response:

JsonNode error =
objectMapper.readTree(response.text());
assertEquals(
"Invalid credentials",
error.get("message").asText()
);

This makes the API test suite much more meaningful than simply checking whether the endpoint returns 200.


API Testing with Query Parameters

Playwright also supports query parameters.

For example:

GET /users?page=2

Using Java:

APIResponse response = request.get(
"/users",
RequestOptions.create()
.setQueryParam("page", "2")
);

You can then validate:

assertEquals(200, response.status());

Playwright’s Java RequestOptions supports configuring query parameters for API requests.


API + UI Test Chaining

This is where Playwright becomes particularly interesting.

Imagine your UI test requires a user to exist before the test starts.

Traditionally, you might:

  1. Open the application
  2. Navigate to registration
  3. Fill in the form
  4. Submit the form
  5. Wait for the user to be created
  6. Continue with the actual test

That’s a lot of UI interaction just to create test data.

With Playwright API testing, we can create the user directly through the backend.

API
Create User
Browser
Login
Perform UI Test

For example:

APIResponse response = request.post(
"/users",
RequestOptions.create()
.setData(userData)
);
assertEquals(201, response.status());

Then launch the browser:

Browser browser =
playwright.chromium().launch();
BrowserContext context =
browser.newContext();
Page page =
context.newPage();

Now navigate to the application:

page.navigate("https://example.com");

The API has prepared the required state before the UI test begins.

Playwright’s official documentation specifically describes using API requests to prepare server-side state before visiting a web application and to validate server-side post-conditions after browser actions.


UI Test Followed by API Validation

The reverse is also extremely useful.

Suppose the UI performs an action:

User clicks "Create Order"

Instead of validating everything through the UI, we can verify the backend state using an API.

UI Action
Create Order
API Request
GET /orders/{id}
Validate Order

This gives us a much stronger end-to-end test.

For example:

page.getByRole(
AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Create Order")
).click();

Then:

APIResponse response =
request.get("/orders/" + orderId);
assertEquals(200, response.status());

Now we are validating both sides of the application:

Frontend behavior + backend state.


Sharing Authentication Between API and UI

One of the more powerful Playwright capabilities is that API and browser contexts can share authentication state.

Playwright documents that storage state can be obtained from an authenticated APIRequestContext and then used when creating a BrowserContext.

For example:

APIRequestContext requestContext =
playwright.request().newContext();
requestContext.get("/login");
String state =
requestContext.storageState();

That state can then be used when creating a browser context:

BrowserContext context =
browser.newContext(
new Browser.NewContextOptions()
.setStorageState(state)
);

Conceptually:

API Login
Authenticated State
Browser Context
Already Authenticated UI

This can eliminate repetitive UI login steps and make test execution significantly faster.


APIRequestContext vs BrowserContext.request()

There are two useful approaches in Playwright.

Standalone API context

APIRequestContext request =
playwright.request().newContext();

This gives you an isolated API request context.

Browser context request

You can also access the request context associated with a browser context:

APIRequestContext request =
context.request();

A request context obtained from a BrowserContext shares the browser context’s cookie jar.

This is useful when API and UI interactions need to operate with the same session.

Playwright documents both approaches and notes that Page.request() is a shortcut for the request context associated with the page’s browser context.


A Practical API Test Class

Let’s combine some of these concepts into a simple JUnit 5 example.

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.playwright.*;
import org.junit.jupiter.api.*;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserApiTest {
private Playwright playwright;
private APIRequestContext request;
private ObjectMapper objectMapper;
@BeforeAll
void setup() {
playwright = Playwright.create();
objectMapper = new ObjectMapper();
request = playwright.request().newContext(
new APIRequest.NewContextOptions()
.setBaseURL("https://api.example.com")
.setExtraHTTPHeaders(
Map.of(
"Content-Type",
"application/json"
)
)
);
}
@Test
void shouldCreateUser() throws Exception {
Map<String, Object> user =
new HashMap<>();
user.put("name", "John Doe");
user.put("email", "john@example.com");
APIResponse response =
request.post(
"/users",
RequestOptions.create()
.setData(user)
);
assertEquals(201, response.status());
JsonNode jsonResponse =
objectMapper.readTree(response.text());
assertEquals(
"John Doe",
jsonResponse.get("name").asText()
);
}
@AfterAll
void tearDown() {
if (request != null) {
request.dispose();
}
if (playwright != null) {
playwright.close();
}
}
}

This structure gives us a clean starting point for building a reusable API automation framework.


Recommended Project Structure

For a real-world Playwright + Java automation framework, I would avoid putting all API logic directly inside test classes.

A cleaner structure could be:

src
└── test
└── java
├── config
│ └── ConfigManager.java
├── api
│ ├── ApiClient.java
│ ├── UserApi.java
│ └── AuthApi.java
├── models
│ ├── User.java
│ └── LoginRequest.java
├── pages
│ ├── LoginPage.java
│ └── DashboardPage.java
└── tests
├── UserApiTest.java
├── LoginTest.java
└── UserJourneyTest.java

The idea is to separate:

API Layer
Models
UI Page Objects
Tests

This makes the framework easier to maintain as the test suite grows.


Why Use Playwright for API Testing?

There are already excellent API testing tools available.

So why would a team consider using Playwright?

The biggest advantage is unification.

If your team is already using Playwright for browser automation, you can use the same ecosystem for API testing.

Instead of:

Selenium → UI
REST Assured → API

you could have:

Playwright → UI + API

That can simplify:

  • Framework maintenance
  • Authentication handling
  • Test data creation
  • API + UI workflows
  • CI/CD execution
  • Test project structure
  • Developer onboarding

However, that doesn’t mean Playwright automatically replaces every API-specific framework.

If your organization has a mature REST Assured framework with extensive custom utilities, reporting, schema validation, contract testing, and integrations, migrating everything just because Playwright supports API testing may not be worthwhile.

The decision should be based on the requirements of your automation architecture.


Playwright API Testing vs REST Assured

For Java automation engineers, one obvious comparison is Playwright API Testing vs REST Assured.

FeaturePlaywrightREST Assured
REST API testingYesYes
GET/POST/PUT/DELETEYesYes
Request headersYesYes
AuthenticationYesYes
JSON validationYesYes
API + UI testingExcellentRequires separate UI tool
Browser automationExcellentNo
Java supportYesYes
API-focused ecosystemGrowingVery mature
Full-stack Playwright workflowExcellentRequires additional framework

The biggest differentiator is not simply whether both can send a GET request.

They can.

The more interesting question is:

Do you want your API and UI automation to live in the same testing ecosystem?

If the answer is yes, Playwright becomes a compelling option.


Best Practices for API Testing with Playwright

When building a Playwright API automation framework, keep the following practices in mind.

1. Don’t hardcode URLs

Use:

.setBaseURL(baseUrl)

and environment-specific configuration.

For example:

DEV
QA
STAGING
PROD

should not require modifying test code.


2. Don’t hardcode credentials

Avoid:

String token = "my-secret-token";

Use environment variables or a secure secrets-management mechanism.

For example:

String token =
System.getenv("API_TOKEN");

3. Create reusable API clients

Instead of:

request.post(...)

inside every test, create classes such as:

UserApi
OrderApi
AuthApi
ProductApi

For example:

public class UserApi {
private final APIRequestContext request;
public UserApi(APIRequestContext request) {
this.request = request;
}
public APIResponse createUser(
Map<String, Object> user) {
return request.post(
"/users",
RequestOptions.create()
.setData(user)
);
}
}

Now the test becomes much cleaner:

APIResponse response =
userApi.createUser(user);

4. Validate more than status codes

Don’t stop at:

assertEquals(200, response.status());

Also validate:

  • Response body
  • JSON fields
  • Headers
  • Business rules
  • Error messages
  • Data relationships

A 200 OK response does not automatically mean the API behaved correctly.


5. Use API calls for test-data setup

If creating test data through the UI takes 30 seconds, but the same operation takes 200 milliseconds through an API, don’t make every test pay the UI cost.

Use the API to prepare the state.

Then use the UI to test the actual user journey.


Conclusion

API testing doesn’t have to live in a completely separate automation world.

With Playwright + Java, API and UI automation can work together in the same framework.

Use APIs to create data.

Use APIs to authenticate.

Use the UI to validate user journeys.

Use APIs again to verify backend state.

That combination can produce faster, cleaner, and more reliable end-to-end tests.

And that is where API Testing with Playwright becomes genuinely interesting.

Related Articles

✓ Playwright Cloud Execution BrowserStack & LambdaTest

✓ Playwright Architecture Explained

✓ Playwright Setup with TypeScript

✓ Playwright Setup with Java

✓ Playwright Locator Strategies

✓ Playwright Auto-Waiting Mechanism

✓ Complete Playwright Tutorial


Discover more from Rotebit

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply