Files
skills/docs/observability/monitor/health-check/src/http-check/http-check.md
2026-05-29 08:20:56 +01:00

2.7 KiB

http-check/http-check

(no submodules)

Purpose

createHttpCheck returns a CheckFn that probes an HTTP endpoint and reports healthy when the response status appears in expectedStatusCodes. It is the standard building block for "is upstream X reachable?" probes — used to check downstream APIs, gateways, internal dependency surfaces, and anything else with a /health or /status endpoint. The factory accepts an injectable fetchImpl so tests never touch real network sockets, and an injectable Clock so responseTime is deterministic.

Features

  • Method, headers, and expected-status-code overrides via the HttpCheckConfig argument.
  • AbortController-driven per-request timeout that maps to responseTime + the human-readable "HTTP check timed out after Xms" message.
  • Network errors are returned as unhealthy with details.error containing the raw message — not thrown.
  • Zod boundary validation: empty url, empty method, non-positive timeout all throw HealthCheckError(INVALID_OPTIONS).
  • fetchImpl defaults to globalThis.fetch bound to globalThis; tests pass a stub.

Usage: Basic

import { createHttpCheck } from "@suaveplan/health-check";

const check = createHttpCheck({ url: "https://upstream.example/health" });
const result = await check();

Usage: Advanced

import { createHttpCheck } from "@suaveplan/health-check";

const check = createHttpCheck(
    {
        url: "https://internal.api/health",
        method: "HEAD",
        headers: { authorization: `Bearer ${token}` },
        timeout: 1_500,
        expectedStatusCodes: [200, 204],
        fetchImpl: instrumentedFetch,
    },
    { clock: () => performance.now() },
);

API Reference

  • createHttpCheck(config, options?) → CheckFn.
  • config: HttpCheckConfig — url required; method, headers, timeout, expectedStatusCodes, fetchImpl optional.
  • options.clock?: Clock — overrides Date.now for response-time measurement.

Implementation Notes

The check never re-throws. Network errors, abort errors, and unexpected status codes are all funnelled into CheckResult objects so the HealthChecker can record them uniformly. Abort detection is case-insensitive on "abort" / "timeout" and also consults controller.signal.aborted so adapters that surface only a generic error message still classify correctly. The responseTime is measured between the clock readings around fetchImpl so it includes DNS, TCP, TLS, and the server's processing time — matching how operators read latency dashboards. The factory is pure: it validates options once and returns a closure that captures the normalised config, so the per-call cost is just the fetch + a small amount of bookkeeping.