Claude Code Skill
API Test Writer
Use when writing automated API tests or integration tests for REST or GraphQL endpoints, testing from an OpenAPI/Swagger spec or Postman collection, or checking status codes, response schemas, auth and error handling — Supertest, pytest + httpx, REST Assured, Postman/Newman and others.
Install
npx skills add WST2002/claude-code-skills --skill api-test-writer
Or copy skills/api-test-writer into ~/.claude/skills/.
Overview
API tests check the contract clients depend on: status codes, response shape, validation, authorization and side effects. They are faster and more stable than UI tests, so most functional coverage belongs here.
Method
- Inventory the endpoints from routes, controllers or the OpenAPI spec: method, path, auth, request schema, responses.
- Match the project's tooling: existing test framework and HTTP client (Supertest for Node,
httpx/requestswith pytest, REST Assured for Java, Newman for Postman collections). Follow existing test structure. - Write cases per endpoint using the matrix below.
- Control data: create what each test needs through the API or factories, clean up afterwards, use unique values to allow parallel runs.
- Run the suite and confirm each new test fails when the behavior is broken (change an expected value once to check).
Case matrix per endpoint
| Category | Cases |
|---|---|
| Success | Valid request → correct status (200/201/204), body matches schema, headers (Location, Content-Type) |
| Validation | Missing required field, wrong type, out-of-range, too long, invalid format → 400/422 with field-level errors |
| Authentication | No token, expired token, malformed token → 401 |
| Authorization | Other user's resource (IDOR), insufficient role → 403 or 404 |
| Not found | Unknown ID → 404 with the standard error shape |
| Conflicts | Duplicate unique value, stale version → 409 |
| Side effects | Record created/updated in the database, event or email queued, idempotent retry does not duplicate |
| Lists | Pagination, filters, sorting, empty results, max page size |
Example (Node, Supertest + Vitest)
import request from "supertest";
import { describe, it, expect } from "vitest";
import { app } from "../src/app";
import { createUser, tokenFor } from "./factories";
describe("POST /orders", () => {
it("creates an order and returns 201 with a Location header", async () => {
const user = await createUser();
const res = await request(app)
.post("/orders")
.set("Authorization", `Bearer ${tokenFor(user)}`)
.send({ items: [{ sku: "SKU-1", quantity: 2 }] });
expect(res.status).toBe(201);
expect(res.headers.location).toMatch(/^\/orders\/\w+$/);
expect(res.body).toMatchObject({ status: "pending", items: [{ sku: "SKU-1", quantity: 2 }] });
});
it("rejects quantity 0 with a field error", async () => {
const user = await createUser();
const res = await request(app)
.post("/orders")
.set("Authorization", `Bearer ${tokenFor(user)}`)
.send({ items: [{ sku: "SKU-1", quantity: 0 }] });
expect(res.status).toBe(422);
expect(res.body.errors).toContainEqual(expect.objectContaining({ field: "items[0].quantity" }));
});
});
Common mistakes
- Only testing the happy path.
- Asserting the whole response with a snapshot that includes IDs and timestamps.
- Tests that depend on data created by another test.
- Never testing authorization with a second user.
- Hitting production or shared environments with destructive tests.