Understanding CRUD

CRUD stands for Create, Read, Update, Delete — the four basic operations for persistent data storage. Nearly every API endpoint maps to one of these operations:

CRUDHTTP MethodExampleTypical Status
CreatePOSTPOST /users201 Created
ReadGETGET /users/42200 OK
UpdatePUT / PATCHPUT /users/42200 OK
DeleteDELETEDELETE /users/42204 No Content

Testing CRUD operations systematically ensures that the API correctly handles the entire lifecycle of a resource — from creation to deletion.

Testing Create (POST)

Happy Path Tests

POST /api/users
Content-Type: application/json

{
  "name": "Alice Johnson",
  "email": "alice@example.com",
  "role": "developer"
}

Verify:

  • Response status is 201 Created
  • Response body contains the created resource with a generated id
  • All submitted fields are present in the response
  • Server-generated fields exist (id, createdAt, updatedAt)
  • Location header points to the new resource URL
  • Fetching the resource via GET returns the same data

Validation Tests

ScenarioExpected
Missing required field (name)400 with clear error message
Empty required field ("")400 with validation error
Invalid email format400/422 with format error
String where number expected400 with type error
Value exceeding max length400 with length error
Extra unknown fieldsIgnored or 400 (depends on API design)

Uniqueness Tests

ScenarioExpected
Duplicate email409 Conflict
Duplicate name (if unique)409 Conflict
Case sensitivity (alice@test.com vs Alice@test.com)Depends on API design

Boundary Tests

  • Maximum field lengths (255 chars for name, etc.)
  • Special characters: Unicode, emojis, HTML tags, SQL injection strings
  • Minimum values: empty arrays, zero quantities
  • Maximum payload size

Testing Read (GET)

Single Resource

GET /api/users/42

Verify:

  • Returns 200 OK with complete user data
  • All expected fields are present
  • Data types are correct (number for id, string for name)
  • Sensitive fields are excluded (password, internal IDs)

Collection (List)

GET /api/users?page=1&limit=20&sort=name&order=asc

Verify:

  • Returns array of resources
  • Pagination metadata is present (total, page, limit, pages)
  • Sorting works correctly
  • Filtering returns only matching resources
  • Default pagination applies when no params sent

Edge Cases

ScenarioExpected
Non-existent ID (GET /users/99999)404 Not Found
Invalid ID format (GET /users/abc)400 or 404
Negative ID (GET /users/-1)400 or 404
Page beyond results (?page=9999)200 with empty array
Very large limit (?limit=100000)Capped at max or 400

Testing Update (PUT / PATCH)

PUT — Full Replacement

PUT /api/users/42
Content-Type: application/json

{
  "name": "Alice Smith",
  "email": "alice.smith@example.com",
  "role": "senior-developer"
}

Verify:

  • All fields are replaced with new values
  • Omitted optional fields are reset to defaults or removed
  • updatedAt timestamp changes
  • id and createdAt remain unchanged
  • GET after PUT returns the updated data

PATCH — Partial Update

PATCH /api/users/42
Content-Type: application/json

{
  "role": "senior-developer"
}

Verify:

  • Only the specified field changes
  • All other fields remain exactly as before
  • updatedAt timestamp changes

Update Edge Cases

ScenarioExpected
Update non-existent resource404 Not Found
Update with invalid data400 with validation error
Update read-only fields (id, createdAt)400 or fields ignored
Concurrent updates (two PUTs simultaneously)Last write wins or 409
Update to duplicate unique value409 Conflict

Testing Delete (DELETE)

Standard Delete

DELETE /api/users/42

Verify:

  • Returns 204 No Content (or 200 OK with confirmation)
  • GET for deleted resource returns 404
  • Resource no longer appears in list endpoint
  • Related resources are handled correctly (cascade or orphan protection)

Delete Edge Cases

ScenarioExpected
Delete non-existent resource404 Not Found
Delete already-deleted resource404 Not Found
Delete resource with dependencies409 or cascade delete
Delete without authorization401/403

End-to-End CRUD Flow Test

The most important test is the complete lifecycle:

1. POST /users → Create user → Save ID
2. GET /users/{id} → Verify user exists with correct data
3. GET /users → Verify user appears in list
4. PUT /users/{id} → Update all fields
5. GET /users/{id} → Verify update applied
6. PATCH /users/{id} → Partial update one field
7. GET /users/{id} → Verify only that field changed
8. DELETE /users/{id} → Remove user
9. GET /users/{id} → Verify 404
10. GET /users → Verify user no longer in list

This flow tests data persistence, consistency, and cleanup across the entire lifecycle.

Data Relationships

When resources have relationships (user has many orders), test:

  • Creating a child resource with valid parent ID
  • Creating a child resource with invalid parent ID (should fail)
  • Deleting a parent with existing children (cascade behavior)
  • Fetching parent includes/excludes children as documented
  • Updating parent does not affect child data

Hands-On Exercise

Using JSONPlaceholder (https://jsonplaceholder.typicode.com):

  1. Full CRUD lifecycle: Create a post, read it, update it with PUT, partial update with PATCH, delete it, verify deletion
  2. Validation testing: Try creating a post with missing fields, wrong types, empty values
  3. Relationship testing: Create a post, then create comments for that post. What happens when you delete the post?
  4. List testing: Test pagination, filtering by userId, and verify response structure for GET /posts

Key Takeaways

  • CRUD operations form the backbone of API testing — every resource goes through create, read, update, delete
  • Always verify data persistence by following POST with GET to confirm the resource actually exists
  • Test both PUT (full replacement) and PATCH (partial update) to ensure they behave differently as expected
  • End-to-end CRUD flow tests catch integration bugs that individual operation tests may miss
  • Don’t forget edge cases: non-existent resources, duplicate entries, cascade deletes, and concurrent updates