RizTech Academy logo
RizTech Academy
API TestingLesson 1 of 430 min

HTTP for testers: requests, responses and status codes

Behind almost every app you test — the mobile app, the web dashboard — there is an API: the server the app talks to over HTTP to fetch and change data. A great deal of the most valuable testing a QA does happens at this layer, below the screen, because it is where the real logic and the real data live. To test an API you must understand HTTP, and the good news is there is not much of it. This lesson is HTTP for testers: requests, responses, and status codes — the vocabulary the rest of the module builds on.

Why test the API at all?

When you tap "Send money" in an app, the app does not do the work itself — it sends an HTTP request to a server, the server does the work (checks the balance, moves the money, records it) and sends back a response, and the app shows you the result. The screen is a thin layer over the API; the logic and the data are on the server.

That is why API testing matters so much:

  • It is where the logic is. Validation, calculations, permissions, the money movement — all decided by the API. A bug there is a real bug, whatever the screen shows.
  • It is faster and more precise than the UI. You send a request and read the response directly, in milliseconds, with no waiting for screens to load. You can test a hundred input combinations at the API in the time one takes through the UI.
  • It is more stable. APIs change less often than screens, so API tests break less (a point the automation modules return to).
  • The UI cannot even reach some cases. An API might accept a value the app's form prevents you typing — and if the server does not also reject it, that is a bug (never trust the client to validate; the API-test-design lesson).

So a QA who can test the API finds bugs a UI-only tester cannot, faster, and closer to the cause.

A request: what you send

An HTTP request has four parts, and you control all of them:

  • The method (verb) — what you want to do:
    • GET — fetch data, changing nothing (read a transaction, list users).
    • POST — create something (a new transaction, a new user).
    • PUT / PATCH — update something (PUT replaces, PATCH changes some fields).
    • DELETE — remove something.
    • GET is safe (no change) and GET/PUT/DELETE are idempotent (doing it twice has the same effect as once) — properties that matter for the retry and money-flow testing you have already met.
  • The URL (endpoint) — what you are acting on, e.g. https://api.example.in/transactions/42. It often carries path parameters (/42, the id) and query parameters (?status=pending&page=2, filters — the same URL state you tested on the web).
  • Headers — metadata about the request: Content-Type: application/json (the body's format), Authorization: Bearer <token> (who you are — the auth lesson), and more.
  • The body — the data you send, usually JSON, on POST/PUT/PATCH. For example:
    { "amount": 500, "to": "9876543210", "note": "rent" }
    

A request is therefore method + URL + headers + body, and testing an API is largely sending deliberately chosen combinations of those four and checking the response.

A response: what you get back

The server replies with three things you check:

  • The status code — a three-digit number saying how it went (below).
  • The headers — metadata (content type, rate-limit info, etc.).
  • The body — the data, again usually JSON: the created record, the list, or an error message.

Every one of these is a testing target: the right status code, the right body, sensible headers.

Status codes: the first thing to check

Status codes are grouped by their first digit, and knowing the groups is most of what you need:

  • 2xx — success. 200 OK (fine, here is the data), 201 Created (POST created a resource), 204 No Content (success, nothing to return, e.g. a DELETE).
  • 3xx — redirection. The resource is elsewhere; the client is redirected. Less common in API testing.
  • 4xx — you (the client) got it wrong. 400 Bad Request (malformed / invalid input), 401 Unauthorized (not authenticated — no/invalid token), 403 Forbidden (authenticated but not allowed — the permission/role concern), 404 Not Found (no such resource), 409 Conflict (clashes with current state), 422 Unprocessable (well-formed but semantically invalid). 4xx means the request was rejected on purpose — and testing that the API returns the right 4xx for bad input is core API testing.
  • 5xx — the server got it wrong. 500 Internal Server Error (the server crashed / a bug), 503 Service Unavailable. A 5xx is almost always a bug — the server should have handled the situation and returned a 4xx, not fallen over. Seeing a 500 where you sent bad input (which should be a 400) is a classic finding.

The single most useful reflex in API testing: send a bad request and check you get the right 4xx, not a 500 and not a misleading 200. An API that returns 200 OK for input it should have rejected, or 500 for input it should have politely refused, is buggy — and only checking the status code reveals it.

Check your work

Why test the API. The screen is a thin layer over an HTTP API where the logic and data live; testing there is faster, more precise and more stable than the UI, and reaches cases the UI cannot (e.g. input the form blocks but the server must still reject — never trust the client).

A request = method + URL + headers + body. Methods: GET (read, safe), POST (create), PUT/PATCH (update), DELETE (remove); GET/PUT/DELETE are idempotent, POST is not. URL carries path params (/42) and query params (?status=pending). Headers carry Content-Type and Authorization. Body is usually JSON.

A response = status code + headers + body (usually JSON) — all three are testing targets.

Status codes. 2xx success (200 OK, 201 Created, 204 No Content); 4xx client error, on purpose (400 bad input, 401 unauthenticated, 403 forbidden, 404 not found, 409 conflict, 422 unprocessable); 5xx server error, almost always a bug (500). Key reflex: bad input should return the right 4xx, never a 500 and never a misleading 200.

Practice

  1. For an app you know, describe one action as an HTTP request: its method, URL (with any path/query params), the headers it needs, and the body it sends.
  2. Match each to a status code: a successful fetch; a POST that creates a record; deleting something with nothing to return; sending invalid JSON; requesting with no auth token; requesting someone else's record; requesting a record that does not exist.
  3. Explain why a 500 in response to obviously bad input is itself a bug, and what status the API should have returned instead.
  4. Explain why GET is "safe" and why POST is not idempotent — and why that matters when a request is retried (link it to the money-flow lesson).
  5. Given a query URL /transactions?status=failed&from=2026-01-01, say what you are asking the server for, and one invalid value for each parameter you would test.

Official documentation

Next: testing an API by hand with Postman.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship