You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds a "Content encoding" section under Server configuration covering
both directions, the two limits and their defaults, the media types that
qualify, and the deliberate non-goals. Adds Caveats entries for the two
consequences a handler author can be surprised by: a strong ETag now
spans two byte streams, and throwing mid-stream produces a valid gzip
trailer over a short body rather than a framing error.
Also corrects the architecture notes in CLAUDE.md, which still described
a filter chain that no longer exists — ExceptionFilter on the spec
context, the request body stashed as an exchange attribute, and a static
`Request.bytes(exchange)` helper — and mentioned neither SecurityFilter
nor ExtrasRouter.
Copy file name to clipboardExpand all lines: CLAUDE.md
+11-8Lines changed: 11 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,20 +26,23 @@ Java 25 is required (see `.java-version`). The server uses thread-per-request wi
26
26
Request flow when `OpenApiServer` boots (`src/main/java/com/retailsvc/http/OpenApiServer.java`):
27
27
28
28
1.`HttpServer` is created on a port with a virtual-thread-per-task executor.
29
-
2. A single `HttpContext` is registered at `spec.basePath()` (the first `servers[].url` path from the OpenAPI doc). A catch-all `/` context returns 404.
30
-
3. Three filters run in order on every request:
31
-
-`ExceptionFilter` — wraps the chain; delegates uncaught exceptions to the user-supplied `ExceptionHandler` (default in `Handlers`).
32
-
-`RequestPreparationFilter` — reads the raw request body, stashes it as an exchange attribute, runs OpenAPI parameter + body validation via `DefaultValidator`, and stores the resolved `operationId` on the exchange.
33
-
-`DispatchHandler` — looks up the `HttpHandler` registered for that `operationId` in the user-supplied map and invokes it. Handler coverage is verified at boot, so the lookup never returns `null`.
29
+
2. One `HttpContext` is registered per spec binding at `spec.basePath()` (the first `servers[].url` path from the OpenAPI doc). Unless a binding owns `/`, a catch-all `/` context serves extra routes via `ExtrasRouter` and 404s everything else; `ExceptionFilter` wraps that context only.
30
+
3. On a binding context, two filters run in order, then the handler:
31
+
-`RequestPreparationFilter` — reads the request body through `RequestBodyReader` (which inflates a gzip `Content-Encoding` under a size cap), resolves the route, runs OpenAPI parameter + body validation via `DefaultValidator`, and binds the resulting `Request` into the `DispatchHandler.CURRENT` scoped value. It renders its own failures through the `ExceptionHandler` rather than relying on `ExceptionFilter`.
32
+
-`SecurityFilter` — enforces the spec's `securitySchemes` / `security`, re-binding the `Request` with resolved principals. It writes its 401/403 responses straight to the exchange.
33
+
-`DispatchHandler` — looks up the `RequestHandler` registered for the resolved `operationId` in the user-supplied map and invokes it, applying interceptors and response decorators. Handler coverage is verified at boot, so the lookup never returns `null`.
34
+
35
+
Every response except `SecurityFilter`'s rejections is written by `ResponseRenderer`, which is also where response gzip coding is applied.
34
36
35
37
Key abstractions:
36
38
37
39
-`com.retailsvc.http.spec.Spec` — parsed from a consumer-supplied `Map<String, Object>` via `Spec.from(raw)`. No JSON library dependency in the library itself; callers use Gson, Jackson, SnakeYAML, etc. to produce the map.
-`com.retailsvc.http.validate.DefaultValidator` — single class using `switch` pattern-match over `Schema` subtypes. Validation failures produce RFC 7807`application/problem+json` 400 responses.
41
+
-`com.retailsvc.http.validate.DefaultValidator` — single class using `switch` pattern-match over `Schema` subtypes. Validation failures produce RFC 9457`application/problem+json` 400 responses.
40
42
-`com.retailsvc.http.internal.Router` — two indexes: exact path map and templated path list. Resolves `operationId` + extracted path variables for each request.
41
-
-`JsonMapper` — `@FunctionalInterface`; single method `Object mapFrom(byte[])`. Callers supply a lambda (see README).
42
-
-`com.retailsvc.http.Request` — static helper; `Request.bytes(exchange)` returns raw body bytes, `Request.parsed(exchange)` returns the `Object` produced by the `JsonMapper`.
43
+
-`TypeMapper` — per-media-type request parsing and response writing; registered via `Builder.bodyMapper(...)`, with `GsonTypeMapper` auto-registered when Gson is on the classpath.
44
+
-`com.retailsvc.http.Request` — an immutable record-like carrier built from primitives (body bytes, path parameters, raw query string, a header lookup function), never the `HttpExchange`. `bytes()` returns the decoded body, `parsed()` the object produced by the `TypeMapper`.
45
+
-`com.retailsvc.http.internal.RequestBodyReader` / `ResponseCompression` — inbound and outbound gzip. See the README's "Content encoding" section for the policy.
0 commit comments