Skip to content

Commit 84d27c3

Browse files
committed
docs: scrub internal-library references from health-handler spec
1 parent d29f625 commit 84d27c3

1 file changed

Lines changed: 24 additions & 27 deletions

File tree

docs/superpowers/specs/2026-05-20-health-handler-design.md

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
## Problem
77

88
Services built on this library need a `/health` endpoint that reports
9-
overall health plus per-dependency status. The internal `hii-generate-health-java`
10-
library already provides the check-running machinery (`HealthCheckService`,
11-
`HealthCheck`, `HealthCheckResult`, `Status`) and a documented JSON shape:
9+
overall health plus per-dependency status. The expected wire format is:
1210

1311
```json
1412
{
@@ -20,8 +18,9 @@ library already provides the check-running machinery (`HealthCheckService`,
2018
```
2119

2220
We want a ready-to-use `HttpHandler` in this repo that produces that exact
23-
shape, **without** taking a compile-time dependency on the health library.
24-
Callers should be able to wire it up in one line.
21+
shape. The handler must not depend on any specific health-check provider —
22+
callers supply the data through a `Supplier`, so they can plug in whatever
23+
mechanism (off-the-shelf or in-house) computes their dependency statuses.
2524

2625
## Goals
2726

@@ -32,21 +31,20 @@ Callers should be able to wire it up in one line.
3231
- Never propagates a probe failure as a 500 — a throwing `Supplier` yields
3332
`Down` + empty dependency list + 503.
3433
2. Define small public records `HealthOutcome` and `Dependency` in
35-
`com.retailsvc.http` that mirror the health library's data shape on the wire,
36-
so this repo stays decoupled from the library.
34+
`com.retailsvc.http` that own the wire shape, so this library has no
35+
runtime or compile-time dependency on any specific health-check provider.
3736
3. Reuse existing infrastructure (`MethodLimitedHandler`, hand-rolled
3837
JSON rendering á la `ProblemDetailRenderer`). No new third-party deps.
3938

4039
## Non-goals
4140

42-
- Direct integration with `HealthCheckService` (callers adapt the library's
43-
`HealthCheckResult` to `HealthOutcome` in a one-line lambda; that adapter
44-
lives in the consuming service, not here).
45-
- Caching of probe results (the health library already supplies
46-
`CachingHealthCheck`).
41+
- Bundling or running health checks. Callers compute their own outcome
42+
(typically by adapting whatever check-runner they use into a
43+
`HealthOutcome`) and pass it in via the `Supplier`.
44+
- Caching of probe results. If a caller's checks are expensive, they
45+
memoize on their side of the `Supplier`.
4746
- A configurable wire format — the field names `outcome`, `dependencies`,
48-
`id`, `status` and the string values `Up` / `Down` are fixed to match the
49-
library's documented contract.
47+
`id`, `status` and the string values `Up` / `Down` are fixed.
5048
- Configurable Content-Type or status codes — fixed at `application/json` +
5149
200/503.
5250
- An integration test — unit coverage is sufficient; `MethodLimitedHandler`
@@ -76,8 +74,8 @@ public record Dependency(String id, String status) {
7674
}
7775
```
7876

79-
`HealthOutcome.isUp()` is case-insensitive so callers that pass through a
80-
library-style "Up" or a custom-cased "UP" both work.
77+
`HealthOutcome.isUp()` is case-insensitive so callers that pass `"Up"`,
78+
`"UP"`, or `"up"` all map to a healthy 200 response.
8179

8280
### Public API — `Handlers.healthHandler`
8381

@@ -117,26 +115,25 @@ remaining control characters below `0x20`.
117115
### Caller-side wiring (illustrative, not part of this repo)
118116

119117
```java
120-
HealthCheckService service = new HealthCheckService();
121-
// register checks…
122-
123118
server = OpenApiServer.builder()
124119
.spec(spec)
125120
.jsonMapper(mapper)
126121
.handlers(operationHandlers)
127122
.addHandler("/health", Handlers.healthHandler(() -> {
128-
HealthCheckResult r = service.check();
129-
return new HealthOutcome(
130-
r.outcome(),
131-
r.dependencies().stream()
132-
.map(s -> new Dependency(s.id(), s.status()))
133-
.toList());
123+
// Caller computes per-dependency statuses however they choose
124+
// and adapts the result into HealthOutcome / Dependency.
125+
List<Dependency> deps = List.of(
126+
new Dependency("jdbc", checkDatabase() ? "Up" : "Down"),
127+
new Dependency("cache", checkCache() ? "Up" : "Down"));
128+
String outcome = deps.stream().allMatch(d -> "Up".equalsIgnoreCase(d.status()))
129+
? "Up" : "Down";
130+
return new HealthOutcome(outcome, deps);
134131
}))
135132
.build();
136133
```
137134

138-
The adapter lambda is the only place that knows about both libraries — which
139-
is exactly where the coupling belongs.
135+
The `Supplier` is the only place that knows how to compute health, which is
136+
exactly where any third-party integration belongs.
140137

141138
## Error handling
142139

0 commit comments

Comments
 (0)