Skip to content

Commit b891e86

Browse files
authored
feat: Add extra handlers with builder (#51)
* docs: Design for extra (non-OpenAPI) handlers + builder * docs: Note README updates in extra-handlers design * feat: Add ClasspathResourceHandler for static resource serving * feat: Add Handlers.aliveHandler and Handlers.specHandler * refactor: Use HttpURLConnection constants in alive/spec handlers * feat: Add OpenApiServer.Builder with extra-handler support * fix: Use responseLength=-1 for empty-body status responses sendResponseHeaders(code, 0) triggers chunked transfer encoding for empty bodies; -1 is correct for status-only responses with no body. Affects notFoundHandler and the NotFound/MethodNotAllowed/default branches of defaultExceptionHandler. * test: Integration coverage for extra handlers and builder * docs: Builder and extra-handlers usage in README * style: Apply Google Java Formatter to GetDataHandler * refactor: Hoist builder setup out of assertThatThrownBy lambdas SonarQube java:S5778 — each throwing lambda should contain only one invocation that could throw a runtime exception. * test: Direct unit tests for ClasspathResourceHandler * build: Drop deprecated <silent> parameter from dependency-plugin maven-dependency-plugin 3.10.0 deprecates the <silent> POM parameter in favour of the -q CLI flag; removing it silences the build warning. * refactor: Drop redundant eq() matchers in ClasspathResourceHandlerTest SonarQube java:S6068 — when every verify() argument is wrapped in eq(), pass raw values instead. The eq() import is retained for the one call that mixes eq() with longThat(), where matchers must be used uniformly.
1 parent f646566 commit b891e86

16 files changed

Lines changed: 1654 additions & 13 deletions

README.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ public class YourServerLauncher {
8383
handlers.put("get-data", new GetDataHandler());
8484
handlers.put("post-data", new PostDataHandler());
8585

86-
new OpenApiServer(spec, mapper, handlers, Handlers.defaultExceptionHandler());
86+
var server = OpenApiServer.builder()
87+
.spec(spec)
88+
.jsonMapper(mapper)
89+
.handlers(handlers)
90+
.exceptionHandler(Handlers.defaultExceptionHandler())
91+
.build();
8792
}
8893
}
8994
```
@@ -95,6 +100,35 @@ Map<String, Object> raw = new Yaml().load(Files.newInputStream(Path.of("openapi.
95100
```
96101
The rest is identical.
97102

103+
### Extra (non-OpenAPI) handlers
104+
105+
Mount handlers at arbitrary paths outside the OpenAPI spec — useful for liveness probes,
106+
serving the spec document itself, or any other operational endpoint that should not be subject
107+
to OpenAPI parameter / body validation.
108+
109+
``` java
110+
var server = OpenApiServer.builder()
111+
.spec(spec)
112+
.jsonMapper(mapper)
113+
.handlers(handlers)
114+
.addHandler("/alive", Handlers.aliveHandler())
115+
.addHandler("/schemas/v1/openapi.yaml",
116+
Handlers.specHandler("/schemas/v1/openapi.yaml"))
117+
.build();
118+
```
119+
120+
Extra handlers bypass OpenAPI validation but are still wrapped in the configured
121+
`ExceptionHandler`, so any uncaught exception is rendered using the same error envelope as
122+
API routes.
123+
124+
Built-in helpers:
125+
- `Handlers.aliveHandler()` — 204 No Content on `GET`/`HEAD`, 405 otherwise.
126+
- `Handlers.specHandler(classpathResource)` — serves a classpath resource (content-type
127+
inferred from extension). Throws `IllegalArgumentException` at construction if the resource
128+
is missing.
129+
130+
The original public constructors remain available for back-compat.
131+
98132
## Features
99133
- OpenAPI specification support
100134
- Automatic request body parsing for JSON arrays and objects

0 commit comments

Comments
 (0)