feat(core): add any() route registration, warn on undocumented OpenAPI routes, log unhandled 500s
Publish Maven packages / publish (push) Failing after 3m35s
Publish Maven packages / publish (push) Failing after 3m35s
FlashRegistrar#any() registers a handler under every HTTP method for verb-indifferent handlers (e.g. a reverse proxy). OpenApiExtension now warns when a class-based handler has no @ApiOperation instead of silently omitting it from the spec. AbstractRouter's default production exception handler now logs unhandled exceptions server-side instead of only returning a JSON 500. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3d743b34ce
commit
74169e40f4
+7
-1
@@ -10,6 +10,7 @@ import dev.relism.flash.extension.RouteEvent;
|
|||||||
import dev.relism.flash.http.ContentType;
|
import dev.relism.flash.http.ContentType;
|
||||||
import dev.relism.flash.http.HttpMethod;
|
import dev.relism.flash.http.HttpMethod;
|
||||||
import dev.relism.flash.routing.Route;
|
import dev.relism.flash.routing.Route;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates and serves an OpenAPI 3.0 spec and Swagger UI under a configurable base path.
|
* Generates and serves an OpenAPI 3.0 spec and Swagger UI under a configurable base path.
|
||||||
@@ -34,6 +35,7 @@ import dev.relism.flash.routing.Route;
|
|||||||
* .start();
|
* .start();
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class OpenApiExtension implements FlashExtension {
|
public class OpenApiExtension implements FlashExtension {
|
||||||
|
|
||||||
private static final String YAML_CONTENT_TYPE = "application/yaml";
|
private static final String YAML_CONTENT_TYPE = "application/yaml";
|
||||||
@@ -124,7 +126,11 @@ public class OpenApiExtension implements FlashExtension {
|
|||||||
if (handlerClass == null) return; // lambda route: no annotation metadata
|
if (handlerClass == null) return; // lambda route: no annotation metadata
|
||||||
|
|
||||||
ApiOperation op = handlerClass.getAnnotation(ApiOperation.class);
|
ApiOperation op = handlerClass.getAnnotation(ApiOperation.class);
|
||||||
if (op == null) return;
|
if (op == null) {
|
||||||
|
log.warn("{} {} ({}) has no @ApiOperation — omitted from the OpenAPI spec",
|
||||||
|
event.method(), event.path(), handlerClass.getSimpleName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
builder.addOperation(routeOf(event), op, handlerClass);
|
builder.addOperation(routeOf(event), op, handlerClass);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ public abstract class FlashRegistrar<SELF extends FlashRegistrar<SELF>> {
|
|||||||
public final SELF purge (String path, SimpleHandler.FunctionalHandler h, Middleware... mw) { return route(HttpMethod.PURGE, path, h, mw); }
|
public final SELF purge (String path, SimpleHandler.FunctionalHandler h, Middleware... mw) { return route(HttpMethod.PURGE, path, h, mw); }
|
||||||
public final SELF query (String path, SimpleHandler.FunctionalHandler h, Middleware... mw) { return route(HttpMethod.QUERY, path, h, mw); }
|
public final SELF query (String path, SimpleHandler.FunctionalHandler h, Middleware... mw) { return route(HttpMethod.QUERY, path, h, mw); }
|
||||||
|
|
||||||
|
/** Registers {@code h} under every {@link HttpMethod}: for handlers indifferent to verb (e.g. a proxy). */
|
||||||
|
public final SELF any(String path, SimpleHandler.FunctionalHandler h, Middleware... mw) {
|
||||||
|
for (HttpMethod m : HttpMethod.values()) route(m, path, h, mw);
|
||||||
|
return (SELF) this;
|
||||||
|
}
|
||||||
|
|
||||||
public final SELF getWith (String path, SimpleHandler.FunctionalHandler h, MiddlewareNode... mw) { return route(HttpMethod.GET, path, h, mw); }
|
public final SELF getWith (String path, SimpleHandler.FunctionalHandler h, MiddlewareNode... mw) { return route(HttpMethod.GET, path, h, mw); }
|
||||||
public final SELF postWith (String path, SimpleHandler.FunctionalHandler h, MiddlewareNode... mw) { return route(HttpMethod.POST, path, h, mw); }
|
public final SELF postWith (String path, SimpleHandler.FunctionalHandler h, MiddlewareNode... mw) { return route(HttpMethod.POST, path, h, mw); }
|
||||||
public final SELF putWith (String path, SimpleHandler.FunctionalHandler h, MiddlewareNode... mw) { return route(HttpMethod.PUT, path, h, mw); }
|
public final SELF putWith (String path, SimpleHandler.FunctionalHandler h, MiddlewareNode... mw) { return route(HttpMethod.PUT, path, h, mw); }
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import dev.relism.flash.Flash;
|
|||||||
import dev.relism.flash.http.ContentType;
|
import dev.relism.flash.http.ContentType;
|
||||||
import dev.relism.flash.http.HttpMethod;
|
import dev.relism.flash.http.HttpMethod;
|
||||||
import dev.relism.flash.template.ErrorPages;
|
import dev.relism.flash.template.ErrorPages;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
* <p><b>Registration</b>: use {@link FlashApp} — the single
|
* <p><b>Registration</b>: use {@link FlashApp} — the single
|
||||||
* public registration API. {@link #doRegister} is an infrastructure method.
|
* public registration API. {@link #doRegister} is an infrastructure method.
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public abstract class AbstractRouter {
|
public abstract class AbstractRouter {
|
||||||
|
|
||||||
/** Eagerly validates and compiles this route graph before traffic is accepted. */
|
/** Eagerly validates and compiles this route graph before traffic is accepted. */
|
||||||
@@ -59,6 +61,7 @@ public abstract class AbstractRouter {
|
|||||||
return ErrorPages.renderException(req, ex);
|
return ErrorPages.renderException(req, ex);
|
||||||
}
|
}
|
||||||
: (ex, req, res) -> {
|
: (ex, req, res) -> {
|
||||||
|
log.error("Unhandled exception in {} {}", req.method(), req.path(), ex);
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.type(ContentType.JSON);
|
res.type(ContentType.JSON);
|
||||||
return JSON_500;
|
return JSON_500;
|
||||||
|
|||||||
Reference in New Issue
Block a user