Actual Code All articles
Code Quality

Postman Returns 200, Production Returns Chaos: Closing the Gap in Your API Testing

Actual Code
Postman Returns 200, Production Returns Chaos: Closing the Gap in Your API Testing

Photo: This image includes elements from this file:, Public domain, via Wikimedia Commons

There's a special kind of dread that comes from a Slack ping at 07:40 on a Monday: checkout is down, customers are angry, and yet every single test in your suite is green. If you've worked on any API of decent size, you've lived this. The uncomfortable truth is that most of us test our APIs in conditions so pristine they barely qualify as testing at all.

The Happy Path Is a Fiction

Think about how a typical API request actually behaves in the wild versus how we test it. In Postman or an integration test, you get a fast, reliable connection, a warm server, a cooperative database and a payload you hand-crafted yourself. In reality, your users are on a train passing through a tunnel outside Warrington, their phone is switching from Wi-Fi to mobile data mid-request, and your Lambda has gone cold because nobody's touched that endpoint since Friday.

The result is a whole class of failures that never appear in your test suite:

None of these are exotic. They're Tuesday. But they're invisible to a test suite built entirely on the happy path.

A Worked Example: Hulme Analytics

Let's ground this in something concrete. Imagine Hulme Analytics, a fictional Manchester SaaS that lets independent shops track footfall and sales. Their public API is consumed by till systems, mobile apps and the occasional spreadsheet glued together with Zapier. It works beautifully in Postman. It falls over regularly in production.

Their problems are the classic ones. A till in a rural Scottish shop with patchy broadband times out after 10 seconds, retries, and creates duplicate sale records because the original write actually succeeded. A cold-started endpoint in their reporting service occasionally blows past the mobile app's timeout, so users see an error for data that did, in fact, arrive. And every so often a partner sends a date field as "tomorrow" because, well, someone's integration code does that.

Here's how they — and you — can close the gap.

Step One: Contract Testing, Not Just Example Testing

Postman tests your implementation against your expectations. Contract testing tests the agreement between provider and consumer, which is a different and much more valuable thing.

With a tool like Pact, Hulme Analytics' mobile team writes a consumer contract describing exactly what fields the app needs, what types they'll be, and what happens when a field is missing. The backend then verifies it can honour that contract on every CI run. Suddenly, the breaking change where someone renamed footfall_count to visits gets caught in a pull request instead of in a one-star App Store review.

The real win is the must_include and state-machine style expectations: contracts force you to specify behaviour for missing fields, wrong types and empty collections. That's precisely the territory Postman's happy-path examples never venture into.

Step Two: Replay Real Traffic Locally

Once you have contracts pinned down, the next layer is realism. Tools like WireMock, Prism or Mountebank let you record actual production traffic (sanitised, obviously — you're handling UK personal data, so mind GDPR and tokenise anything identifying) and replay it locally.

When Hulme Analytics replayed a week of recorded traffic against a fresh build, they discovered within an hour that a partner was sending timestamps with a milliseconds precision their parser silently truncated — which had been quietly skewing their peak-hour reporting for months. No hand-written test would ever have caught that, because no human would have thought to write it.

Pair this with chaos injection: add latency, drop connections mid-response, return 500s at random. WireMock's fault injection or toxiproxy make this a ten-minute job. If your client code doesn't fall over when you do this, you've earned some confidence. If it does — better to find out on your machine than in a shop's till system on a Saturday.

Step Three: Simulate the Network You Actually Have

UK mobile networks are a special kind of hostile. Your users are moving between masts, hitting train tunnels, and dealing with network congestion at half-time on a Saturday. Chrome DevTools and tc (traffic control on Linux) let you simulate 3G latency, packet loss and throttled bandwidth.

Run your mobile client against your locally-replayed API on a throttled connection and watch what happens. Does it retry with exponential backoff, or does it hammer the endpoint? Does it handle a request that succeeds server-side but fails client-side? This single exercise catches more production bugs than a month of extra unit tests.

Step Four: Make Cold Starts Boring

If you're on serverless, cold starts are a fact of life. Test for them deliberately: deploy to a staging environment that's been idle overnight, then measure first-request latency against your client timeout. If the numbers don't fit, you have three honest options — provisioned concurrency, a ping to keep things warm (with the cost trade-offs that implies), or moving genuinely latency-sensitive endpoints off cold-start-prone infrastructure. What you can't do is pretend it isn't happening because Postman always showed you a warm response.

Ship the Environment, Not Just the Code

The recurring theme here is that the gap between test and production isn't a testing problem — it's an environment problem. Postman isn't lying, exactly; it's just answering a much easier question than the one your users are asking.

Start small. Add one contract test for your most-used endpoint. Replay one day of sanitised traffic before your next release. Simulate a bad connection for ten minutes. None of this requires a platform team or a six-month initiative, and each piece pays for itself the first time it catches a bug that would otherwise have surfaced as an angry email from a shop owner in Sheffield.

Your users don't live in Postman. Your tests shouldn't either.

All Articles

Related Articles

Your package.json Is a Shopping List You Never Audit: Fixing Supply Chain Hygiene on a Budget

Your package.json Is a Shopping List You Never Audit: Fixing Supply Chain Hygiene on a Budget

Fifty Repos, Fifty Lessons: What a Year of Auditing British SME Codebases Taught Us

Fifty Repos, Fifty Lessons: What a Year of Auditing British SME Codebases Taught Us

Nobody Wants to Hear This: Your Ten-Year-Old Rails App Doesn't Need a Rewrite

Nobody Wants to Hear This: Your Ten-Year-Old Rails App Doesn't Need a Rewrite