Try the REST API Checker

The 200 Response Is the Least Useful Thing You Can Test

The successful request is the least informative test. Response headers, error paths and duplicate-request behaviour are where API integrations actually break.

October 12, 2026 8 min read
Share: Facebook WhatsApp LinkedIn Email
The 200 Response Is the Least Useful Thing You Can Test

The Request That Works Until It Doesn't

You test an endpoint. It returns 200 with the expected body. You ship.

Then in production it starts failing for some users and not others, or works on the first call and not the second, or returns correct data that your client can't parse.

The request you tested wasn't the request your client sends. Testing an API properly means testing what the whole exchange looks like — headers included — rather than whether the happy path returns data.

Headers Carry Half the Contract

The REST API Checker lets you send requests and inspect the full response:

  1. Enter the URL and method.
  2. Add headers and a body if needed.
  3. Read the status, headers and body.

The response headers are where a large share of the useful information lives, and they're routinely ignored in favour of the body.

Content-Type

Tells you what the body actually is. A mismatch between this and what your client expects causes parse failures that look like data problems.

Watch for text/html on an endpoint that should return JSON — that's usually an error page from a proxy or load balancer, not from your API. A 200 status with an HTML body is a classic symptom of a request never reaching the application.

The charset parameter matters too. application/json; charset=utf-8 is explicit; bare application/json relies on the JSON spec's UTF-8 default, which is fine but occasionally trips up older clients.

Cache-Control and ETag

Determines whether responses are cached and for how long.

A GET endpoint returning Cache-Control: no-store on every call is doing unnecessary work. One returning a long max-age on data that changes frequently will serve stale responses.

ETag enables conditional requests. Send If-None-Match with a previous ETag and a 304 response means nothing changed — no body transferred. Worth checking whether your API supports this, because it's a substantial bandwidth saving on polling clients.

Rate limit headers

Conventions vary, but common patterns include:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1789012345
Retry-After: 60

Retry-After is the standardised one and appears on 429 and 503 responses. It can be a number of seconds or an HTTP date.

Read these before you hit the limit, not after. An integration that ignores them and retries aggressively on 429 makes the problem worse and can get the client blocked.

WWW-Authenticate

On a 401, this header tells you what authentication scheme the server expects. A 401 without it is unhelpfully vague; with it, you know whether to send a bearer token, basic credentials, or something else.

CORS headers

Access-Control-Allow-Origin and related headers only matter for browser clients, but they cause a distinctive confusion: a request that works perfectly from a command line tool fails from a browser with an opaque error.

That's not an API failure. It's the browser enforcing a policy the server didn't grant.

Status Codes That Get Misused

Several status codes are routinely used for the wrong thing, which makes debugging harder than it should be.

200 with an error in the body. An API returning {"success": false, "error": "not found"} with a 200 status is lying to every piece of infrastructure between it and the client. Caches, monitoring and retry logic all key off status codes.

404 vs 403. A 404 for a resource the caller isn't authorised to see is a deliberate choice — it avoids confirming the resource exists. A 404 for a resource that doesn't exist is the ordinary meaning. Both are valid; knowing which your API does matters when debugging.

400 vs 422. 400 for malformed syntax (unparseable JSON), 422 for syntactically valid content that fails validation. Many APIs use 400 for both, which is acceptable but less informative.

500 for client errors. A server error status for a validation failure sends the client into retry logic for something that will never succeed.

302 vs 307/308. A 302 historically caused clients to change POST to GET on redirect. 307 and 308 preserve the method. If a POST silently becomes a GET after a redirect, this is why.

429 vs 503. 429 means you specifically are being rate limited. 503 means the service is unavailable generally. Different retry strategies.

Idempotency: The Thing Nobody Tests

An operation is idempotent if performing it multiple times has the same effect as performing it once.

GET     idempotent — reading doesn't change state
PUT     idempotent — setting a value to X twice gives X
DELETE  idempotent — deleting twice leaves it deleted
POST    NOT idempotent — creating twice creates two things
PATCH   depends on the patch semantics

This matters because networks fail in ambiguous ways. A client sends a POST, the request succeeds server-side, and the response is lost. The client doesn't know whether it worked. If it retries, it creates a duplicate. If it doesn't, it may have lost the operation.

The standard solution is an idempotency key: the client generates a unique identifier per logical operation and sends it with the request. The server stores the key with the result, and a repeat request with the same key returns the stored result rather than performing the operation again.

POST /payments
Idempotency-Key: 8f14e45f-ea47-4b0e-9c2d-1a3f7b2e9c04

Test this explicitly. Send the same request twice with the same key and confirm you get one resource, not two. Send it twice with different keys and confirm you get two. Plenty of APIs document idempotency support and implement it incompletely.

Testing the Error Paths

The successful request is the least informative test. What to check:

Missing authentication. Should return 401 with WWW-Authenticate, not 500 or 403.

Invalid authentication. Expired token, malformed token, token for a different audience. Each should fail distinctly.

Wrong method. A DELETE on a read-only endpoint should return 405 with an Allow header listing permitted methods.

Malformed body. Invalid JSON should return 400, not a stack trace.

Missing required fields. Should return a validation error naming the fields, not a generic failure.

Wrong content type. Sending text/plain to an endpoint expecting JSON should return 415.

Oversized payload. Should return 413, not time out.

Nonexistent resource. 404 with a useful body.

Rate limit exceeded. 429 with Retry-After.

Error responses are also where APIs most often leak information — stack traces, internal paths, database error messages, framework versions. Checking what your errors actually return is a security review as much as a functional one.

Timeouts and Retries

Two settings that determine how an integration behaves under stress.

Connect timeout — how long to wait to establish a connection. Should be short, typically a few seconds. A connection that hasn't established quickly usually isn't going to.

Read timeout — how long to wait for a response. Depends on what the endpoint does. A quick lookup should respond in well under a second; a report generation endpoint might legitimately take much longer.

Retry only what's safe. Retrying a GET is harmless. Retrying a POST without an idempotency key risks duplicates.

Back off exponentially with jitter. Retrying immediately, at a fixed interval, from many clients simultaneously produces a synchronised retry storm that keeps a struggling service down.

delay = min(base × 2^attempt, cap) + random(0, jitter)

Respect Retry-After when present. It's the server telling you exactly when to come back.

Cap the retries. Three or four attempts. Beyond that you're not recovering from a transient failure, you're hammering a broken service.

Practical Tips

Always inspect response headers, not just the body.

Test error paths before shipping. They're where the surprises are.

Verify idempotency behaviour for any operation that creates or charges something.

Check what your errors leak. Stack traces in production responses are a real exposure.

Test with the exact headers your client sends, including Accept, Content-Type and any authentication.

Confirm 304 handling if your API supports ETags — it's an easy performance win that's often left unimplemented on the client side.

Watch for HTML responses on JSON endpoints. It means something in front of your API is answering.

FAQ

Why does my request work in a testing tool but fail in the browser? Almost always CORS. The browser enforces a policy the server hasn't granted; command-line tools don't enforce it.

What's the difference between 400 and 422? 400 for malformed syntax, 422 for valid syntax that fails validation. Many APIs use 400 for both.

What is an idempotency key? A client-generated unique identifier sent with a request so the server can recognise and deduplicate retries of the same logical operation.

Should I retry a failed POST? Only with an idempotency key, or after confirming the operation didn't succeed. Otherwise you risk duplicates.

Why am I getting HTML from a JSON endpoint? Usually an error page from a proxy, load balancer or web server — meaning the request didn't reach your application.

What does Retry-After mean? The server is telling you how long to wait before retrying. It appears on 429 and 503 responses and should be respected.

The Takeaway

Testing whether an endpoint returns data is the easiest test available and the least informative. The response headers, the error paths, and the behaviour on a duplicate request are where integrations actually break — and all three are checkable in a few minutes before anything ships.

Test REST APIs directly in your browser free with the REST API Checker at sadiqbd.com — no sign-up, instant results.

Ask AI about this article
Share: Facebook WhatsApp LinkedIn Email

REST API Checker

Free, instant results — no sign-up required.

Open REST API Checker →
Similar Tools
JSON Diff Timestamp Converter Base64 Encoder/Decoder HTML Entities JWT Decoder URL Encoder/Decoder JSON Unescape & Cleaner Number Base Converter
API Rate Limiting: How It Works, How to Read Rate Limit Headers, and Exponential Backoff Strategies
Developer
API Rate Limiting: How It Works, How to Read Rate Limit Headers, and Exponential Backoff Strategies
API Versioning: URL Paths, Headers, Query Strings, and Why "Just Change the Endpoint" Always Comes Back to Haunt You
Developer
API Versioning: URL Paths, Headers, Query Strings, and Why "Just Change the Endpoint" Always Comes Back to Haunt You
The Most Revealing API Tests Aren't Successful Requests — A Systematic Error-Path Testing Guide
Developer
The Most Revealing API Tests Aren't Successful Requests — A Systematic Error-Path Testing Guide
GraphQL's Introspection Query Is an Attacker's Best Friend — Batching, Nested Query DoS, and Persisted Queries
Developer
GraphQL's Introspection Query Is an Attacker's Best Friend — Batching, Nested Query DoS, and Persisted Queries