@@ -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.
787788Built-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
797848Gson on the classpath for request/response JSON, SnakeYAML on the classpath for the spec, one
0 commit comments