API AUTOMATIONBEGINNER

Part 3: Mastering CRUD Operations in Playwright API Testing

Master CRUD operations in Playwright API testing. Learn POST, GET, PUT, PATCH, DELETE with real examples, test.describe(), test.step(), and enterprise best practices using JSONPlaceholder.

iff Solution Academy July 17, 2026 14 min read Updated July 2026
Playwright API Testing CRUD REST API POST GET PUT PATCH DELETE JSONPlaceholder

Introduction

In the previous chapter, you learned how to configure Playwright for API testing and send your first HTTP GET request.

Now it's time to build something closer to what you'll find in a real enterprise automation framework.

Every REST API revolves around four fundamental operations:

  • Create
  • Read
  • Update
  • Delete

These operations are commonly known as CRUD. Whether you're testing an e-commerce application, banking system, healthcare platform, or SaaS product, you'll spend most of your time automating these API operations.

By the end of this chapter, you'll know how to automate each CRUD operation using Playwright while following enterprise-level best practices.

Understanding CRUD Operations

CRUD represents the four basic operations performed on data.

text
| Operation | HTTP Method | Purpose                |
| --------- | ----------- | ---------------------- |
| Create    | POST        | Create a new resource  |
| Read      | GET         | Retrieve existing data |
| Update    | PUT / PATCH | Modify existing data   |
| Delete    | DELETE      | Remove data            |

Almost every REST API follows this design. Examples include customer management systems, employee portals, banking applications, inventory systems, social media platforms, and e-commerce websites.

Learning CRUD automation means you've already mastered most of REST API testing.

Test API Used in This Tutorial

To keep things simple, we'll use the public REST API:

text
https://jsonplaceholder.typicode.com

It provides realistic responses without requiring authentication, which makes it perfect for learning Playwright API automation. Later in this series, we'll work with authenticated enterprise APIs.

Project Structure

Our project now looks like this:

text
playwright-api-framework/

tests/
   posts.spec.ts

playwright.config.ts

package.json

We'll place all CRUD examples inside a single test file.

CREATE Request (POST)

A POST request creates a new resource. Create the following test.

tests/posts.spec.ts
import { test, expect } from "@playwright/test";

test("Create a new post", async ({ request }) => {

    const response = await request.post("/posts", {

        data: {

            title: "Playwright API Automation",

            body: "Enterprise Framework",

            userId: 1

        }

    });

    expect(response.status()).toBe(201);

    const post = await response.json();

    expect(post.title).toBe("Playwright API Automation");

    expect(post.userId).toBe(1);

});

Understanding the POST Request

The request body is passed using the data property.

ts
data:{
   title:"Playwright API Automation"
}

Playwright automatically converts the JavaScript object into JSON before sending it to the server. No manual serialization is required.

READ Request (GET)

Let's retrieve a specific record.

tests/posts.spec.ts
test("Retrieve a single post", async ({ request }) => {

    const response = await request.get("/posts/1");

    expect(response.status()).toBe(200);

    const body = await response.json();

    expect(body.id).toBe(1);

    expect(body.userId).toBe(1);

});

This verifies the status code, that the resource exists, and the response data.

Retrieving Multiple Records

Fetching collections is equally simple.

tests/posts.spec.ts
test("Retrieve all posts", async ({ request }) => {

    const response = await request.get("/posts");

    expect(response.status()).toBe(200);

    const posts = await response.json();

    expect(Array.isArray(posts)).toBeTruthy();

    expect(posts.length).toBeGreaterThan(0);

});

Instead of validating every record, validate important business rules. Examples include ensuring the collection isn't empty, required fields exist, record count is correct, sorting order is valid, and there are no duplicate values.

UPDATE Request (PUT)

PUT replaces the entire resource.

tests/posts.spec.ts
test("Update a post", async ({ request }) => {

    const response = await request.put("/posts/1",{

        data:{

            id:1,

            title:"Updated Title",

            body:"Updated Body",

            userId:1

        }

    });

    expect(response.status()).toBe(200);

    const body=await response.json();

    expect(body.title).toBe("Updated Title");

});

PUT should generally include every field of the resource. Think of it as replacing the existing object with a brand-new version.

PATCH Request

PATCH updates only selected fields.

tests/posts.spec.ts
test("Patch a post", async ({ request }) => {

    const response = await request.patch("/posts/1",{

        data:{

            title:"Updated Using PATCH"

        }

    });

    expect(response.status()).toBe(200);

    const body=await response.json();

    expect(body.title).toBe("Updated Using PATCH");

});

Unlike PUT, PATCH sends only the fields you want to modify. Most enterprise APIs prefer PATCH for partial updates.

DELETE Request

Deleting data is straightforward.

tests/posts.spec.ts
test("Delete a post", async ({ request }) => {

    const response = await request.delete("/posts/1");

    expect(response.status()).toBe(200);

});

Some APIs return 200 OK, 202 Accepted, or 204 No Content. Always verify the API documentation before asserting the expected status code.

Complete CRUD Test Suite

A professional CRUD suite usually contains the following tests:

  • Create Post
  • Retrieve Single Post
  • Retrieve All Posts
  • Update Post
  • Patch Post
  • Delete Post

Keeping each operation in its own test improves readability and debugging.

Using test.describe()

Grouping related tests makes reports easier to understand.

tests/posts.spec.ts
test.describe("Posts API",()=>{

   test("Create...",async()=>{});

   test("Retrieve...",async()=>{});

   test("Update...",async()=>{});

   test("Delete...",async()=>{});

});

Your HTML report becomes much cleaner.

Using test.step()

Large API tests can become difficult to debug. Break them into logical steps.

tests/posts.spec.ts
test("Verify User Information",async({request})=>{

   await test.step("Retrieve User",async()=>{

      // API Call

   });

   await test.step("Validate Response",async()=>{

      // Assertions

   });

});

When a failure occurs, Playwright clearly shows which step failed.

Enterprise Best Practices

Keep Tests Independent

Never depend on another test. Avoid chains like Create User, then Update User, then Delete User. If Create fails, every remaining test also fails. Instead, every test should prepare its own data. Independent tests are more reliable and can run in parallel.

Validate Business Rules

Don't stop at expect(response.status()).toBe(200). Also validate IDs, names, status, dates, required fields, and business logic. The response body is just as important as the status code.

Use Meaningful Test Names

A descriptive test name makes reports much easier to read. Instead of test("POST"), prefer test("POST /users creates a new active customer").

Avoid Hardcoded Values

Instead of request.get("/users/1"), store reusable IDs inside test data files, environment files, or fixtures. This makes your framework easier to maintain.

Don't Repeat Request Logic

Instead of writing request.post(...) repeatedly across tests, create reusable API client classes. We'll build those later in this series.

Common Beginner Mistakes

Many engineers make these mistakes during their first API automation project:

  • Verifying only status codes
  • Writing dependent tests
  • Hardcoding URLs
  • Mixing multiple scenarios into one test
  • Ignoring response body validation
  • Using fixed wait times
  • Repeating request logic across multiple files

Avoiding these habits early will save you hundreds of hours as your automation framework grows.

Interview Question

What is the difference between PUT and PATCH?

PUT replaces the complete resource and usually requires sending every field. PATCH updates only specific fields and sends only the properties that need modification. Most REST APIs use PATCH for partial updates because it's more efficient and reduces payload size.

Summary

Congratulations! You can now automate the complete CRUD lifecycle using Playwright.

In this chapter, you learned:

  • Creating resources using POST
  • Retrieving resources using GET
  • Updating resources using PUT
  • Partially updating resources using PATCH
  • Deleting resources using DELETE
  • Organizing CRUD tests
  • Using test.describe() and test.step()
  • Enterprise best practices
  • Common mistakes to avoid

In the next chapter, we'll move beyond public APIs and learn how to authenticate with secure applications using Bearer Tokens, JWT Authentication, API Keys, OAuth, and reusable authentication fixtures—a critical skill for building enterprise-grade Playwright API automation frameworks.

Designing CRUD Tests That Survive Parallelism

A CRUD suite is the first place a naive API framework falls apart. The tempting design is one test that creates a record, a second that reads it, a third that updates it and a fourth that deletes it. It reads beautifully and it is fundamentally broken: the tests are ordered, they cannot run in parallel, and a failure in step one cascades into three misleading failures.

The robust pattern is that every test owns its data. A create test creates and deletes its own record. An update test creates a record in a fixture, updates it, asserts, and the fixture tears it down. Each test is complete on its own, can run on any worker, in any order, and a failure points at exactly one operation. The extra create call costs a few milliseconds; the debugging time it saves is measured in hours.

Uniqueness matters just as much as ownership. If two workers create a user with the email test@example.com, one of them gets a 409 and the failure looks like a product bug. Generate identifiers with a per-test seed — a timestamp plus the worker index plus a short random suffix is enough — and never rely on the database being empty when the run starts.

Common Mistakes

  • Asserting the full response body with toEqual. Servers add fields; your test should assert the fields it cares about with toMatchObject.
  • Deleting test data in the test body instead of a fixture teardown — when the assertion fails, the cleanup never runs and the environment fills with junk.
  • Assuming PUT and PATCH behave the same. PUT usually replaces the resource and silently drops fields you did not send.
  • Checking a delete succeeded by trusting the 204 alone. Follow it with a GET and assert the 404.

Frequently Asked Questions

Should I clean up data if the environment is reset nightly?

Yes. Between resets, accumulated records slow queries and cause pagination-dependent tests to drift. Cleanup in teardown is cheap insurance.

What if the API has no delete endpoint?

Prefer soft-delete or archive endpoints if they exist. Otherwise namespace your data with a recognisable prefix and clean it with a scheduled job rather than leaving it untracked.

How do I test endpoints that depend on another resource?

Create the parent through a fixture, not through another test. Fixtures compose; test ordering does not.

Playwright Framework Series

View all →
  1. 1Getting Started with Playwright: Installation, Setup, and Your First Test
  2. 2Playwright Locators: The Complete Guide with Real-World Examples
  3. 3Playwright Actions: Complete Guide to Click, Fill, Hover, Keyboard, Mouse & File Upload
  4. 4Playwright Assertions Complete Guide: Web-First Assertions, Auto-Retry & Custom Matchers
  5. 5Playwright Auto Waiting: The Complete Guide with Real-World Examples
  6. 6Playwright Fixtures: The Complete Guide with Real-World Examples
  7. 7Playwright Browser Context & Multiple Tabs: The Complete Guide with Real-World Examples
  8. 8Playwright Authentication & Session Management: Complete Guide with Enterprise Examples
  9. 9Playwright Network Interception & API Mocking: Complete Guide with Real-World Examples
  10. 10Playwright Page Object Model (POM): The Complete Guide with Enterprise Examples
  11. 11Page Object Model with Playwright: A Practical Guide
  12. 12How to Build a Robust Professional Playwright Framework from Scratch (Step-by-Step)
  13. 13Building an Enterprise Playwright Framework from Scratch

API Testing Series

View all →
  1. 1Part 1 : Playwright API Testing Tutorial: Build Enterprise-Level API Automation Framework
  2. 2Part 2: Playwright API Testing Tutorial: Setting Up Project & Sending Your First API Request
  3. 3Part 3: Mastering CRUD Operations in Playwright API Testing
  4. 4Part 4: Authentication in Playwright API Testing (Bearer Token, JWT, API Key & Reusable Fixtures)
  5. 5Part 5: Building an Enterprise-Level Playwright API Automation Framework
  6. 6Part 6: API Models, Schema Validation & Test Data Management in Playwright
  7. 7Part 7: Custom Fixtures, Hooks, Logging & Parallel Execution in Playwright API Testing
  8. 8Part 8: Building a Production-Ready Playwright API Framework (Environment Management, CI/CD, Reporting & Best Practices)
  9. 9Part 9: Advanced Playwright API Testing Techniques for Enterprise Automation
  10. 10Part 10: Building a Complete Enterprise Playwright API Automation Framework (Final Part)
  11. 11Playwright Backend Testing Tutorial – REST API, GraphQL, WebSocket, Kafka, Database & Microservices

Recommended Next Articles