Skip to content

Commit b14fe02

Browse files
committed
docs: Mention healthHandler in README with example and response shapes
1 parent d61095a commit b14fe02

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ endpoints declared in an OpenAPI 3.1.x specification. Handlers are pure function
2626
- [Request body content types](#request-body-content-types)
2727
- [Error responses (RFC 7807)](#error-responses-rfc-7807)
2828
- [Extra (non-OpenAPI) handlers](#extra-non-openapi-handlers)
29+
- [Health endpoint](#health-endpoint)
2930
- [Graceful shutdown](#graceful-shutdown)
3031
- [End-to-end example](#end-to-end-example)
3132
- [Local development](#local-development)
@@ -787,11 +788,61 @@ routes.
787788
Built-in helpers:
788789

789790
- `Handlers.aliveHandler()` — 204 No Content on `GET`/`HEAD`, 405 otherwise.
791+
- `Handlers.healthHandler(Supplier<HealthOutcome>)` — readiness probe that aggregates dependency
792+
statuses. See [Health endpoint](#health-endpoint) below.
790793
- `Handlers.resourceHandler(classpathResource)` / `Handlers.resourceHandler(Path)` — streams a
791794
classpath resource or filesystem file (content-type inferred from extension; the stream is
792795
opened and closed per request, and the handler owns its lifecycle). Throws
793796
`IllegalArgumentException` at construction if the resource or file is missing.
794797

798+
### Health endpoint
799+
800+
`Handlers.healthHandler(probe)` mounts a readiness endpoint that aggregates per-dependency
801+
statuses into a single response. The probe is invoked on every request, so it sees current
802+
backend state.
803+
804+
``` java
805+
RequestHandler health = Handlers.healthHandler(() -> new HealthOutcome(List.of(
806+
new Dependency("jdbc", dataSource.isReachable()),
807+
new Dependency("kafka", kafkaClient.isConnected()))));
808+
809+
var server = OpenApiServer.builder()
810+
.spec(spec)
811+
.handlers(handlers)
812+
.extraRoute("/health", health)
813+
.build();
814+
```
815+
816+
Status code derives from the dependency list: `200 OK` when every dependency is up (vacuously
817+
true for an empty list), `503 Service Unavailable` otherwise. The wire shape is the same in both
818+
cases:
819+
820+
``` json
821+
{
822+
"outcome": "Up",
823+
"dependencies": [
824+
{"id": "jdbc", "status": "Up"},
825+
{"id": "kafka", "status": "Up"}
826+
]
827+
}
828+
```
829+
830+
``` json
831+
{
832+
"outcome": "Down",
833+
"dependencies": [
834+
{"id": "jdbc", "status": "Up"},
835+
{"id": "kafka", "status": "Down"}
836+
]
837+
}
838+
```
839+
840+
The body is rendered by a built-in writer — no JSON library on the classpath is required. A
841+
probe that throws or returns `null` is logged at WARN and surfaces as a `Down` response with an
842+
empty dependency list; the exception never reaches the configured `ExceptionHandler`. `GET` and
843+
`HEAD` are accepted; other methods return `405 Method Not Allowed` with an `Allow: GET, HEAD`
844+
header.
845+
795846
## End-to-end example
796847

797848
Gson on the classpath for request/response JSON, SnakeYAML on the classpath for the spec, one

0 commit comments

Comments
 (0)