QASimplifiedby AkashGet Free Interview Pack
← Back to Articles

API Testing Foundations # 2 - HTTP for QA Engineers: Understanding Requests and Responses

21 October 2026

A bug report comes in: “Checkout fails sometimes.”

A tester who only works through the UI reproduces it, attaches a screenshot of a spinner, and assigns it to the frontend team. The frontend team says it’s a backend issue. The backend team says they can’t reproduce it. Three days later, it’s still open.

A tester who understands HTTP opens DevTools, reproduces it once, and finds the POST /api/orders call returning 504 Gateway Timeout after 30 seconds, but only when the cart has more than 20 items. The bug report now has a request, a response, a pattern, and an owner. It gets fixed that sprint.

Same bug, same tester skill level, very different result. The difference is knowing what’s happening underneath the screen.

This article isn’t a protocol textbook. It covers the parts of HTTP that change how you test and how you report bugs.

Why HTTP matters even if you “only do UI testing”

Every modern web and mobile app is a front end talking to APIs over HTTP. When you click a button, the UI is mostly packaging a request and displaying a response.

That means:

  • Most “UI bugs” aren’t UI bugs. The screen is just showing what the API returned.

  • The UI hides information. A generic “Something went wrong” toast might be a 400, a 401, a 409, or a 500. Each one means something completely different.

  • The UI can mislead you. A success message can appear even when the API failed, and a stale value can come from cache.

If you can read HTTP traffic, you stop guessing and start diagnosing.

The request: what the client asks for

An HTTP request has four parts: method, URL, headers, and body.

Method

The method states the intent.

The POST row is where real money is lost. A user double-clicks “Pay,” or the network retries, and two identical POSTs hit the server. Does the customer get charged twice? This is idempotency, and testing it is a valuable check that’s easy to skip.

URL

https://shop.example.com/api/v1/orders/1042?include=items

  • Path (/orders/1042) identifies the resource.

  • Query params (?include=items) filter or shape the result.

The most important test here is simple: change the ID. If logging in as User A and calling /orders/1043 returns User B’s order, you’ve found an Insecure Direct Object Reference (IDOR). It’s one of the most common serious API vulnerabilities, and finding it doesn’t take a security tool. Swapping a number is enough.

Headers

Headers carry context. The ones QA touches most:

  • Authorization: who you are (Bearer token, Basic auth)

  • Content-Type: what format the body is in

  • Accept: what format you want back

  • Cookie: session data from the browser

Negative tests that take very little time:

  • No Authorization header → expect 401

  • Valid token, but for a user without permission → expect 403

  • Expired token → expect 401, with a clear message

  • Wrong Content-Type → expect 415 or 400, not 500

Body

The body carries the payload, usually JSON. This is where input validation gets tested:

  • Required field missing

  • Wrong type ("quantity": "five")

  • Boundaries (0, -1, 99999999)

  • Empty string vs null vs field absent (APIs often treat these three differently, and inconsistently)

  • Extra fields the API doesn’t expect. Are they ignored, rejected, or, worse, saved? ("role": "admin" on a profile update is the classic case.)

The response: what the server says back

A response has a status code, headers, and body. Most weak API tests read only the first.

Status codes: learn the ones that matter

You don’t need all of them. You need to know these well:

The rule to remember: a 500 caused by user input is always a bug. The server should have validated the input and returned a 4xx. A 500 means it didn’t, and that the input reached a part of the code that wasn’t expecting it.

Also watch for the opposite problem: APIs that return 200 for everything and put the error inside the body ({"success": false}). Monitoring, retries, and automation tools all depend on status codes. If the API returns 200 for a failure, all of those tools will treat it as a success.

Response headers

Check these, especially on auth and sensitive endpoints:

  • Content-Type matches what’s actually in the body

  • Set-Cookie for sessions includes HttpOnly (JavaScript can’t read it) and Secure (HTTPS only)

  • Cache-Control: no-store on responses with personal or financial data

  • No headers leaking server versions or internal details

Response body

This is where “status 200, test passed” falls apart. Check:

  • Schema: are the fields, types, and nesting what the contract promises?

  • Values: is the total correct? Is the status right? Is the timestamp in the right timezone?

  • Data exposure: does the user profile response include the password hash, internal IDs, or other users’ data?

  • Error quality: is the message useful to the client, without stack traces, SQL errors, or file paths?

HTTP is stateless, which is why sessions break

HTTP doesn’t remember anything between requests. Every request has to prove who it is, again and again. That’s what cookies and tokens are for.

This is the source of a whole family of bugs testers see regularly:

  • Logged out on page refresh

  • Logged in on one tab, logged out on another

  • Session survives logout (the token still works after the user clicks “Logout”)

  • Token never expires

  • Old token still works after a password change

Each of these can be tested directly at the HTTP level. For example, capture a token, log out, and replay a request with the old token. If it still works, logout is only cosmetic.

Your HTTP testing toolkit

You don’t need anything fancy to start:

  • Browser DevTools → Network tab: watch real traffic, filter by Fetch/XHR, inspect requests and responses, and use “Copy as cURL” to reproduce outside the UI.

  • cURL: the fastest way to replay and tweak a request.

  • Postman / Bruno / Insomnia: organize requests, add assertions, and build collections.

  • Code-based clients: REST Assured, Playwright’s request context, or Python requests for automation.

A workflow that works well in practice:

  1. Reproduce the bug in the browser with DevTools open.

  2. Find the failing request.

  3. Copy as cURL and replay it from the terminal.

  4. Change one thing at a time (body, header, ID) until you isolate the cause.

  5. Attach the request, response, and your finding to the bug.

That’s how “checkout fails sometimes” turns into “POST /orders times out when the cart has more than 20 items.”

Writing better bug reports with HTTP

Compare these two:

“Profile update not working. Screenshot attached.”

“PATCH /api/v1/users/me returns 500 when phone includes a ‘+’ prefix. Same request without ‘+’ returns 200. Request/response attached. Expected: 200, or 400 with a validation message.”

The second one needs no back-and-forth. It names the endpoint, the trigger, the expected result, and the evidence. Developers fix these first because they can start immediately.

A practical HTTP checklist for every endpoint you test

Request side

  • Correct method accepted, wrong methods rejected (405)

  • Missing / invalid / expired auth handled (401/403)

  • Other users’ resource IDs blocked

  • Required, optional, extra, null, and empty fields handled

  • Boundary and type validation returns 4xx, never 5xx

  • Duplicate POSTs don’t create duplicate side effects

Response side

  • Status code is the correct one, not just a 2xx

  • Body matches the schema and the values are correct

  • No sensitive data in body or headers

  • Error messages are helpful and safe

  • Auth cookies have HttpOnly and Secure

  • Response time is acceptable

The takeaway

You don’t need to memorize RFCs to test APIs well. You need to see clearly what goes out and what comes back.

Once you read HTTP easily, three things change. Your bug reports get sharper. Your negative testing gets more thorough. And you stop treating the UI as the source of truth, because you know it’s only showing what the API returned.

Start this week: pick one feature you test daily, open the Network tab, and read every request it makes. You’ll likely find at least one thing you’ve never checked.


Next Wednesday: GET, POST, PUT, PATCH and DELETE with Real Testing Examples