Skip to content

HTTP Fundamentals โ€‹

To test REST APIs you need to master HTTP: it's the language the API uses to tell you whether something went right or wrong, and quite often the status code is itself the bug.

Anatomy of a request and a response โ€‹

โ”€โ”€ Request โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
POST /api/v1/service-orders HTTP/1.1     โ† method + path
Host: api.example.com
Authorization: Bearer eyJhbGc...         โ† headers
Content-Type: application/json

{ "customerId": "C-100", "productId": "fiber-1gbps" }    โ† body

โ”€โ”€ Response โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
HTTP/1.1 201 Created                     โ† status code
Content-Type: application/json
Location: /api/v1/service-orders/42

{ "id": 42, "customerId": "C-100", "productId": "fiber-1gbps", "status": "created" }

HTTP methods โ€‹

MethodUseIdempotent?*Has a body?
GETRead a resourceYesNo
POSTCreate a resource / actionNoYes
PUTReplace an entire resourceYesYes
PATCHPartially modifyNo (in general)Yes
DELETEDeleteYesUsually not

* Idempotent = running it N times produces the same state as running it once. Hugely important for testing: a repeated PUT must not duplicate anything; a repeated POST can create duplicates (does the API guard against that?).

Status codes: the ones a QA cares about โ€‹

2xx โ€” Success โ€‹

  • 200 OK โ€” successful request with a response.
  • 201 Created โ€” resource created (expect a Location header and/or the resource in the body).
  • 204 No Content โ€” success with no response body (typical of DELETE).

4xx โ€” Client error (this is where negative testing lives!) โ€‹

  • 400 Bad Request โ€” malformed request or invalid data.
  • 401 Unauthorized โ€” not authenticated (token missing or invalid).
  • 403 Forbidden โ€” authenticated but without permission. The 401/403 mix-up is a classic bug.
  • 404 Not Found โ€” the resource doesn't exist. Careful: some APIs return 404 instead of 403 to avoid revealing that the resource exists โ€” that's a design decision, and you need to know which one applies.
  • 409 Conflict โ€” state conflict (e.g. creating a duplicate service order for a customer who already has that same service in progress).
  • 422 Unprocessable Entity โ€” correct syntax but semantically invalid data.
  • 429 Too Many Requests โ€” rate limiting.

5xx โ€” Server error โ€‹

  • 500 Internal Server Error โ€” unhandled exception. A 500 triggered by user input is always a bug, no matter how absurd the input: the server must validate and respond with a 4xx.
  • 502 / 503 / 504 โ€” infrastructure problems (gateway, service down, timeout).

The "200 with an error inside" anti-pattern

Some APIs return 200 OK with { "success": false, "error": "..." } in the body. It's bad practice and a trap for testing: never validate only the status code, validate the body too.

Headers worth looking at โ€‹

  • Content-Type โ€” body format (application/json). What happens if I send a different one?
  • Authorization โ€” credentials (Bearer <token>, Basic ...).
  • Location โ€” URL of the freshly created resource (on 201).
  • Cache-Control / ETag โ€” caching. A source of "stale data" bugs.
  • X-Request-Id (or similar) โ€” correlation with logs; gold for reporting API bugs.