Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 3 min read

A 200 response can still break your API integration

An API can be up, fast, and still break every client that depends on it. A field changes from an object to an array. An optional property disappears. A path is renamed in the OpenAPI document. The uptime check stays gr

An API can be up, fast, and still break every client that depends on it.

A field changes from an object to an array. An optional property disappears. A path is renamed in the OpenAPI document.

The uptime check stays green because the server did exactly what it was asked to do: it returned 200 OK.

That gap is what I wanted to monitor.

Uptime answers only one question

A basic status probe can tell you whether:

  • DNS resolved
  • TLS completed
  • the server responded
  • the response arrived within a threshold

Those checks matter, but they do not tell you whether the response still means what your code expects.

Imagine yesterday's payload looked like this:

{
  "customer": {
    "id": "cus_42",
    "status": "active"
  }
}

Today it looks like this:

{
  "customer": [
    {
      "id": "cus_42",
      "status": "active"
    }
  ]
}

Both responses are valid JSON. Both can arrive in 120 ms with a 200. Only one matches a client written for yesterday's contract.

Four kinds of API change

I find it useful to separate dependency failures into four buckets:

  1. Availability β€” status, timeout, TLS, or DNS failures.
  2. Shape β€” a field was added or removed, a type changed, or an object became an array.
  3. Contract β€” an OpenAPI path, method, parameter, or response schema changed.
  4. Behavior β€” the shape stayed the same, but the meaning changed.

The first three can be observed automatically. The fourth usually needs domain-specific assertions.

Keeping these separate also makes alerts easier to reason about. β€œThe endpoint is down” and β€œthe endpoint is up but incompatible” should not arrive as the same vague incident.

Raw diffs create their own problem

A generic JSON diff catches everything, including values that are supposed to change: timestamps, request IDs, counters, ordering, and rotating tokens.

The useful output is not just β€œthese payloads differ.” It is closer to:

{
  "rule": "type_changed",
  "path": "$.customer",
  "before": "object",
  "after": "array",
  "severity": "breaking"
}

That is small enough to use in a webhook, CI check, or incident timeline. More importantly, it tells the person responding where to look.

A practical monitoring loop

For each external API dependency:

  1. Probe a representative endpoint.
  2. Remove known volatile fields.
  3. Derive a normalized response shape.
  4. Compare it with the last accepted observation.
  5. Classify the change.
  6. Keep the evidence needed to reproduce it.
  7. Alert only when a rule says the change matters.

The phrase last accepted observation is important. If every result automatically becomes the new baseline, one malformed response can quietly normalize the failure.

I would also avoid testing with private credentials unless the monitor has a clear data-handling model. Public HTTPS targets and synthetic test accounts are a safer place to start.

What I built from this

I turned this pattern into a small developer API called DependSignal. It probes public APIs for status and latency, compares JSON response shapes and supported OpenAPI contracts, and returns field paths with rule evidence.

I kept the scope narrow on purpose. It is not a replacement for full contract tests or domain assertions. It is another layer for catching upstream drift before a user reports it.

The landing page includes a no-key sample, because a monitoring product should be inspectable before anyone creates credentials:

https://dependsignal.strigsapi.com/

The part I am still tuning is noise. Some teams want every added field; others only care about removals and type changes.

What does your team treat as a breaking API change: status, schema, behavior, or some combination?

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.