1010A lightweight Java library that wraps the JDK's ` com.sun.net.httpserver.HttpServer ` and serves
1111endpoints declared in an OpenAPI 3.1.x specification. Handlers are pure functions registered by
1212` operationId ` ; the framework handles routing, OpenAPI parameter and body validation, JSON
13- (de)serialisation, and RFC 7807 error rendering.
13+ (de)serialisation, and RFC 9457 error rendering.
1414
1515## Table of contents
1616
@@ -27,7 +27,7 @@ endpoints declared in an OpenAPI 3.1.x specification. Handlers are pure function
2727- [ After-response hooks] ( #after-response-hooks )
2828- [ Security] ( #security )
2929- [ Request body content types] ( #request-body-content-types )
30- - [ Error responses (RFC 7807 )] ( #error-responses-rfc-7807 )
30+ - [ Error responses (RFC 9457 )] ( #error-responses-rfc-9457 )
3131- [ Extra (non-OpenAPI) handlers] ( #extra-non-openapi-handlers )
3232 - [ Health endpoint] ( #health-endpoint )
3333- [ Graceful shutdown] ( #graceful-shutdown )
@@ -47,7 +47,7 @@ endpoints declared in an OpenAPI 3.1.x specification. Handlers are pure function
4747 ` ResponseDecorator ` for cross-cutting response headers
4848- OpenAPI ` securitySchemes ` and ` security ` enforcement (` apiKey ` , ` http bearer ` , ` http basic ` ),
4949 with an opt-out for sidecar / gateway authentication
50- - RFC 7807 ` application/problem+json ` validation errors with JSON-Pointer to the failing location
50+ - RFC 9457 ` application/problem+json ` validation errors with an ` errors[] ` array of JSON-Pointers to the failing locations
5151- Built on the JDK's native ` HttpServer ` with thread-per-request behaviour using virtual threads
5252
5353## Maven artifact
@@ -630,7 +630,7 @@ to detect errors.
630630
631631The library parses ` components.securitySchemes ` and the ` security ` requirement lists (root-level
632632and per-operation), extracts the credential per scheme, hands it to a consumer-provided
633- ` SchemeValidator ` callback, and renders RFC 7807 ` application/problem+json ` rejections — 401 for
633+ ` SchemeValidator ` callback, and renders RFC 9457 ` application/problem+json ` rejections — 401 for
634634missing/malformed credentials (with ` WWW-Authenticate ` ), 403 when the validator denies.
635635
636636Supported scheme types in this release:
@@ -870,28 +870,38 @@ case-insensitive):
870870
871871Form-field coercion mirrors the rules already used at the parameter boundary : the wire is
872872string-only by definition, so a property typed as `integer` accepts `"42"` and yields `42`.
873- Coercion failures surface as RFC-7807 `400` responses with a JSON-pointer to the failing field.
873+ Coercion failures surface as RFC-9457 `400` responses with a JSON-pointer to the failing field.
874874
875875Both built-in parsers honour the `charset=` parameter on the `Content-Type` header (default
876876UTF-8). Unknown charsets fall back to UTF-8.
877877
878- # # Error responses (RFC 7807 )
878+ # # Error responses (RFC 9457 )
879879
880880Validation failures — missing required fields, type mismatches, unsupported content types,
881881coercion errors, malformed bodies — produce an `HTTP 400 Bad Request` response with body media
882882type `application/problem+json`, following
883- [RFC 7807 ](https://datatracker.ietf.org/doc/html/rfc7807 ).
883+ [RFC 9457 ](https://datatracker.ietf.org/doc/html/rfc9457) (which obsoletes RFC 7807 ).
884884
885- A single error is reported per request (first failure wins). The response body has these fields :
885+ The top level carries the RFC core members; each individual failure is an entry in an `errors`
886+ array (an RFC 9457 extension member). A non-combinator failure yields a single entry; a
887+ ` oneOf` / `anyOf` failure yields one entry per failed branch, ordered most-likely-cause first
888+ (the branch the payload most resembles) and de-duplicated.
886889
887890| Field | Type | Description |
888891| ---------- | ------- | ---------------------------------------------------------------------------------------- |
889892| `type` | string | Always `about:blank` (no per-error type URI). |
890893| `title` | string | Always `Bad Request`. |
891894| `status` | integer | Always `400`. |
892- | `detail` | string | Human-readable description of the failure (e.g. `expected integer`). |
893- | `pointer` | string | [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901) JSON-Pointer to the failing location (e.g. `/body/age`, `/query/limit`, `/path/id`, or `/body` for body-wide errors). |
895+ | `detail` | string | Human-readable description (a leaf message; for a combinator, `matched 0 of N oneOf branches` or `did not match any anyOf branch`). |
896+ | `errors` | array | One entry per failure; omitted when empty. Each entry has the fields below. |
897+
898+ Each `errors[]` entry :
899+
900+ | Field | Type | Description |
901+ | ---------- | ------- | ---------------------------------------------------------------------------------------- |
902+ | `pointer` | string | [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901) JSON-Pointer to the failing location, as a URI fragment — e.g. `#/age` for a body field, `#/query/limit` / `#/path/id` for parameters, `#/body` for whole-body errors (missing body, unsupported content type), or `#` when the entire body is the wrong type. |
894903| `keyword` | string | The validation rule that failed : ` type` , `required`, `enum`, `pattern`, `format`, `minimum`, `maximum`, `minLength`, `maxLength`, `additionalProperties`, `oneOf`, `anyOf`, `allOf`, `not`, `const`, `content-type`, `decode`, … |
904+ | `detail` | string | Human-readable description of this failure (e.g. `expected integer`). |
895905
896906Example body for `POST /form-echo` with `age=abc` (`age` is declared as `integer`) :
897907
@@ -901,11 +911,31 @@ Example body for `POST /form-echo` with `age=abc` (`age` is declared as `integer
901911 "title": "Bad Request",
902912 "status": 400,
903913 "detail": "expected integer",
904- "pointer": "/age",
905- "keyword": "type"
914+ "errors": [
915+ { "pointer": "#/age", "keyword": "type", "detail": "expected integer" }
916+ ]
917+ }
918+ ` ` `
919+
920+ Example body for a `oneOf` request body that matches no branch — one entry per failed branch,
921+ deepest (most-likely) first :
922+
923+ ` ` ` json
924+ {
925+ "type": "about:blank",
926+ "title": "Bad Request",
927+ "status": 400,
928+ "detail": "matched 0 of 2 oneOf branches",
929+ "errors": [
930+ { "pointer": "#/pet/collar/size", "keyword": "type", "detail": "expected integer" },
931+ { "pointer": "#/pet/bark", "keyword": "type", "detail": "expected boolean" }
932+ ]
906933}
907934` ` `
908935
936+ When several branches fail at the same location for the same reason, those identical entries are
937+ collapsed into one — so a `oneOf` failure can show fewer entries than it has branches.
938+
909939Other error responses :
910940
911941- **404 Not Found** — no route matches the request path (no body).
0 commit comments