A successful HTTP response is not always the service condition you meant to monitor. In this lab, adding an explicit readiness assertion exposed failures that an HTTP-status check could not distinguish.
Can a green HTTP check hide an unhealthy API?
We modelled a small readiness endpoint with a deliberately simple contract: the service is ready only when it returns HTTP 200 and the complete body is {"ready":true}, allowing whitespace. A failed dependency can leave the HTTP handler responding while the application reports {"ready":false}. A status-only rule accepts both.
HTTP 200 describes a successful request. The readiness requirement here is an additional application-level contract that we chose for the experiment. A production readiness endpoint should normally return an appropriate failure status when its required dependencies are unavailable.
One endpoint, five phases, two rules
- The script starts an HTTP server on an automatically assigned loopback port. It makes no external requests and needs no credentials or dependencies.
- Five phases run in order: healthy, dependency failed, missing readiness field, HTTP error and recovered. Each phase receives three GET requests, for 15 actual responses.
- Both rules evaluate the same captured status and body. Status-only requires exactly HTTP 200. Readiness requires HTTP 200 plus the anchored expression below.
- Requests are sequential, without a scheduled check interval. Repetitions check consistency for these fixed fixtures; they are not independent production observations.
^\s*\{\s*"ready"\s*:\s*true\s*\}\s*$The expression intentionally accepts only the small object in our contract. It rejects extra fields, nested objects and a missing or false readiness value. It is not a general JSON validator; use a proper parsed-value check when your response contract is more complex.
What the captured responses showed
Staged failure samples identified as failing
3/9
HTTP status only
9/9
HTTP status + readiness
| Phase | HTTP / body | Status passes | Readiness passes |
|---|---|---|---|
| healthy | 200{"ready":true} | 3/3 | 3/3 |
| dependency-failed | 200{"ready":false} | 3/3 | 0/3 |
| missing-field | 200{} | 3/3 | 0/3 |
| http-error | 503{"ready":false} | 0/3 | 0/3 |
| recovered | 200{"ready":true} | 3/3 | 3/3 |
Both rules passed the six healthy or recovered samples. The status-only rule also passed all six HTTP 200 samples with false or missing readiness. The additional assertion rejected those six and the three HTTP 503 samples. Recovery restored passing results under both rules.
Recorded on 2026-09-06, using Node v24.13.0 on darwin/arm64. The raw file includes each sample timestamp, status, body and both rule outcomes. The table above is generated from that file.
Run the same test on your computer
Use Node.js 22 or later. Download the script, inspect it, then run it in a writable directory. The command writes a new results file in that directory. No account, package install or public server is required.
Download the reproduction script · Download our raw results
node reproduce.mjs > my-results.jsonThe script exits with an error if fixture responses or expected classifications differ. A successful run reports 15 samples, nine staged failures, three failures detected by status alone and nine by readiness. Your timestamps and runtime details will differ. The listener is closed when the test finishes.
For an extension, change the fixture to {"ready":true,"version":"2"}. The strict contract rejects it, so the built-in assertion fails. That is a useful reminder to update monitoring rules deliberately when the response format changes, rather than assuming every extra body check is correct.
Translate the finding into a useful monitor
In 247Monitor API monitoring, use an HTTP check for the expected status. For this exact response contract, configure a keyword monitor with regex matching and the expression above, still requiring HTTP 200. The product supports regex response assertions; the lab script itself does not exercise the hosted product.
- Choose a field that represents a meaningful dependency or operation, rather than a decorative success string.
- Test healthy, false, missing and recovery responses on a non-production endpoint. Confirm both failure and recovery notifications separately.
- Do not substitute a JSON-path existence check for a value assertion: a path can exist while its value is false. A substring such as
readyis also insufficient. - Record the actual polling interval, confirmation policy and notification delay when testing an alert timeline. None of those delays was measured here.
Follow the API setup guide for methods, authentication and checks. Use the uptime and downtime calculator to put a measured outage duration into a time-based availability budget.
What this case study does and does not establish
This test demonstrates a rule-selection failure with real local HTTP responses. It does not measure production uptime, detection speed, delivery of alerts, regional confirmation, customer outcomes or performance against another monitoring service. The fixtures were deliberately chosen to expose the difference; nine out of nine is not a general detection-rate claim.
A strict body rule can create false alarms if it does not match the intended contract. Keep status and meaningful response assertions together, review them when the API changes and test the complete alert path independently. Read our comparison and evidence methodology for how we distinguish observed results from product claims.