refactor(core): make boot and middleware ordering deterministic
This commit is contained in:
+10
-12
@@ -4,8 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
|
||||
import dev.relism.flash.extension.FlashContext;
|
||||
import dev.relism.flash.extension.FlashExtension;
|
||||
import dev.relism.flash.extension.FlashRegistrar;
|
||||
import dev.relism.flash.extension.FlashExtension;
|
||||
import dev.relism.flash.extension.RouteEvent;
|
||||
import dev.relism.flash.http.ContentType;
|
||||
import dev.relism.flash.http.HttpMethod;
|
||||
@@ -65,7 +65,7 @@ public class OpenApiExtension implements FlashExtension {
|
||||
// ── FlashExtension ────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void provide(FlashContext ctx) {
|
||||
public void configure(FlashRegistrar<?> app, FlashContext ctx) {
|
||||
OpenApiBuilder builder = new OpenApiBuilder().title(title).version(version).description(description);
|
||||
OpenApiContributorRegistry registry = new OpenApiContributorRegistry();
|
||||
|
||||
@@ -76,22 +76,20 @@ public class OpenApiExtension implements FlashExtension {
|
||||
// Collect operation metadata from final compiled routes.
|
||||
// This guarantees full runtime paths (namespaces/prefixes/rewrites) in the spec.
|
||||
ctx.addRouteListener(event -> addOperationFromEvent(builder, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routes(FlashRegistrar<?> app, FlashContext ctx) {
|
||||
ObjectMapper jsonMapper = ctx.find(ObjectMapper.class).orElseGet(() -> JsonMapper.builder().build());
|
||||
YAMLMapper yamlMapper = new YAMLMapper();
|
||||
OpenApiBuilder builder = ctx.require(OpenApiBuilder.class);
|
||||
ctx.onReady(() -> {
|
||||
ObjectMapper jsonMapper = ctx.find(ObjectMapper.class).orElseGet(() -> JsonMapper.builder().build());
|
||||
YAMLMapper yamlMapper = new YAMLMapper();
|
||||
OpenApiBuilder resolvedBuilder = ctx.require(OpenApiBuilder.class);
|
||||
|
||||
String jsonPath = basePath + ".json";
|
||||
String yamlPath = basePath + ".yaml";
|
||||
String swaggerPath = basePath + "/swagger";
|
||||
String swaggerHtml = buildSwaggerHtml(jsonPath);
|
||||
|
||||
app.get(jsonPath, (req, res) -> { res.type(ContentType.JSON); return jsonMapper.writeValueAsString(builder.build()); });
|
||||
app.get(yamlPath, (req, res) -> { res.type(YAML_CONTENT_TYPE); return yamlMapper.writeValueAsString(builder.build()); });
|
||||
app.get(swaggerPath, (req, res) -> { res.type(ContentType.TEXT_HTML); return swaggerHtml; });
|
||||
app.get(jsonPath, (req, res) -> { res.type(ContentType.JSON); return jsonMapper.writeValueAsString(resolvedBuilder.build()); });
|
||||
app.get(yamlPath, (req, res) -> { res.type(YAML_CONTENT_TYPE); return yamlMapper.writeValueAsString(resolvedBuilder.build()); });
|
||||
app.get(swaggerPath, (req, res) -> { res.type(ContentType.TEXT_HTML); return swaggerHtml; });
|
||||
});
|
||||
}
|
||||
|
||||
// ── Swagger UI HTML ───────────────────────────────────────────────────────
|
||||
|
||||
+13
-13
@@ -11,7 +11,7 @@ import dev.relism.flash.http.HttpMethod;
|
||||
import dev.relism.flash.models.RequestHandler;
|
||||
import dev.relism.flash.models.Response;
|
||||
import dev.relism.flash.routing.GET;
|
||||
import dev.relism.flash.routing.Middleware;
|
||||
import dev.relism.flash.routing.MiddlewareNode;
|
||||
import dev.relism.flash.websocket.WebSocketEndpoint;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -41,12 +41,10 @@ class OpenApiExtensionTest {
|
||||
void provide_collects_operations_and_routes_serve_json_yaml_swagger() throws Exception {
|
||||
FlashContext ctx = new FlashContext();
|
||||
OpenApiExtension ext = new OpenApiExtension("/docs", "My API", "2.0.0", "desc");
|
||||
ext.provide(ctx);
|
||||
|
||||
emitRoute(ctx, HttpMethod.GET, "/health", "/", HealthHandler.class);
|
||||
|
||||
TestRegistrar app = new TestRegistrar(ctx);
|
||||
ext.routes(app, ctx);
|
||||
ext.configure(app, ctx);
|
||||
emitRoute(ctx, HttpMethod.GET, "/health", "/", HealthHandler.class);
|
||||
ctx.complete();
|
||||
|
||||
assertNotNull(app.route(HttpMethod.GET, "/docs.json"));
|
||||
assertNotNull(app.route(HttpMethod.GET, "/docs.yaml"));
|
||||
@@ -77,9 +75,9 @@ class OpenApiExtensionTest {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
ctx.provide(ObjectMapper.class, mapper);
|
||||
|
||||
ext.provide(ctx);
|
||||
TestRegistrar app = new TestRegistrar(ctx);
|
||||
ext.routes(app, ctx);
|
||||
ext.configure(app, ctx);
|
||||
ctx.complete();
|
||||
|
||||
Response jsonRes = new Response(200, ContentType.NONE);
|
||||
Object jsonBody = app.route(HttpMethod.GET, "/openapi.json").handle(null, jsonRes);
|
||||
@@ -99,10 +97,11 @@ class OpenApiExtensionTest {
|
||||
void collects_full_runtime_path_from_route_event() {
|
||||
FlashContext ctx = new FlashContext();
|
||||
OpenApiExtension ext = new OpenApiExtension();
|
||||
ext.provide(ctx);
|
||||
ext.configure(new TestRegistrar(ctx), ctx);
|
||||
|
||||
emitRoute(ctx, HttpMethod.GET, "/api/v1/users", "/api/v1", ScopedUsersHandler.class);
|
||||
|
||||
ctx.complete();
|
||||
OpenApiBuilder builder = ctx.require(OpenApiBuilder.class);
|
||||
Map<String, Object> spec = builder.build();
|
||||
Map<String, Object> paths = cast(spec.get("paths"));
|
||||
@@ -114,10 +113,11 @@ class OpenApiExtensionTest {
|
||||
void normalizes_double_slash_paths_from_events() {
|
||||
FlashContext ctx = new FlashContext();
|
||||
OpenApiExtension ext = new OpenApiExtension();
|
||||
ext.provide(ctx);
|
||||
ext.configure(new TestRegistrar(ctx), ctx);
|
||||
|
||||
emitRoute(ctx, HttpMethod.GET, "//blogs", "/", ScopedUsersHandler.class);
|
||||
|
||||
ctx.complete();
|
||||
OpenApiBuilder builder = ctx.require(OpenApiBuilder.class);
|
||||
Map<String, Object> spec = builder.build();
|
||||
Map<String, Object> paths = cast(spec.get("paths"));
|
||||
@@ -150,7 +150,7 @@ class OpenApiExtensionTest {
|
||||
private static final class TestRegistrar extends FlashRegistrar<TestRegistrar> {
|
||||
private final FlashContext ctx;
|
||||
private final Map<String, RequestHandler> routes = new HashMap<>();
|
||||
private final List<Middleware> middlewares = new ArrayList<>();
|
||||
private final List<MiddlewareNode> middlewares = new ArrayList<>();
|
||||
|
||||
private TestRegistrar(FlashContext ctx) {
|
||||
this.ctx = ctx;
|
||||
@@ -162,7 +162,7 @@ class OpenApiExtensionTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addRoute(HttpMethod method, String path, RequestHandler handler, List<Middleware> mw) {
|
||||
protected void addRoute(HttpMethod method, String path, RequestHandler handler, List<MiddlewareNode> mw) {
|
||||
routes.put(method.name() + " " + path, handler);
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ class OpenApiExtensionTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addMiddleware(Middleware mw) {
|
||||
protected void addMiddleware(MiddlewareNode mw) {
|
||||
middlewares.add(mw);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user