Upgrade to Javalin 7 and refactor route registration

Updated the dependency to Javalin v7.2.3 and refactored route registration to use the new `RoutesConfig` API. Adjusted `GuildRoutes`, `ActionRoutes`, and `WebApi` to align with updated conventions and centralized route definitions. Improved modularity, reduced redundancy, and ensured backward compatibility by migrating exception and error handler logic. Updated tests to comply with the refactored APIs and structure.
This commit is contained in:
anthorob committed 2026-09-25 06:36:00 -04:00
1 parent 4cf7c47645
commit 36c4acb13a
5 files changed
+30 -27

No files matched your search

+2 -2
View File
@@ -162,7 +162,7 @@
<dependency> <dependency>
<groupId>io.javalin</groupId> <groupId>io.javalin</groupId>
<artifactId>javalin</artifactId> <artifactId>javalin</artifactId>
<version>6.7.0</version> <version>7.2.3</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -202,7 +202,7 @@
<artifactId>gitlab4j-api</artifactId> <artifactId>gitlab4j-api</artifactId>
<version>6.2.0</version> <version>6.2.0</version>
<exclusions> <exclusions>
<!-- Clashes with the Servlet 5 API used by Javalin's Jetty 11 in the shaded jar. --> <!-- Clashes with the Servlet API used by Javalin's Jetty 12 in the shaded jar. -->
<exclusion> <exclusion>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
@@ -6,7 +6,7 @@ package me.bobert.netneutrality.http.server;
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import io.javalin.Javalin; import io.javalin.config.RoutesConfig;
import io.javalin.http.Handler; import io.javalin.http.Handler;
import me.bobert.netneutrality.db.service.GuildServiceProvider; import me.bobert.netneutrality.db.service.GuildServiceProvider;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
@@ -18,7 +18,7 @@ import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* Registers the {@code /actions/*} endpoints on a {@link Javalin} instance. * Registers the {@code /actions/*} endpoints on a {@link RoutesConfig} instance.
*/ */
public final class ActionRoutes { public final class ActionRoutes {
@@ -29,12 +29,12 @@ public final class ActionRoutes {
} }
public static void register( public static void register(
Javalin app, RoutesConfig routes,
Supplier<JDA> jdaSupplier, Supplier<JDA> jdaSupplier,
GuildServiceProvider guildServices, GuildServiceProvider guildServices,
Runnable shutdownHook Runnable shutdownHook
) { ) {
app.get("/actions/status", ctx -> { routes.get("/actions/status", ctx -> {
JDA jda = GuildRoutes.jda(jdaSupplier); JDA jda = GuildRoutes.jda(jdaSupplier);
ctx.json(Map.of( ctx.json(Map.of(
"health", String.valueOf(jda.getStatus()), "health", String.valueOf(jda.getStatus()),
@@ -47,17 +47,17 @@ public final class ActionRoutes {
ctx.result("Shutting down.."); ctx.result("Shutting down..");
scheduleShutdown(shutdownHook); scheduleShutdown(shutdownHook);
}; };
app.post("/actions/shutdown", shutdown); routes.post("/actions/shutdown", shutdown);
app.get("/actions/shutdown", shutdown); routes.get("/actions/shutdown", shutdown);
app.get("/actions/settings/current/{guildId}", ctx -> { routes.get("/actions/settings/current/{guildId}", ctx -> {
Guild guild = GuildRoutes.guild(jdaSupplier, ctx); Guild guild = GuildRoutes.guild(jdaSupplier, ctx);
Map<String, String> settings = guildServices.get(guild).getGuildSettingService().getSettings(); Map<String, String> settings = guildServices.get(guild).getGuildSettingService().getSettings();
ctx.json(Map.of("status", "ok", "settings", settings)); ctx.json(Map.of("status", "ok", "settings", settings));
}); });
app.post("/actions/settings/reload/{guildId}", ctx -> { routes.post("/actions/settings/reload/{guildId}", ctx -> {
Guild guild = GuildRoutes.guild(jdaSupplier, ctx); Guild guild = GuildRoutes.guild(jdaSupplier, ctx);
guildServices.get(guild).getGuildSettingService().reloadSettingsCache(); guildServices.get(guild).getGuildSettingService().reloadSettingsCache();
@@ -6,7 +6,7 @@ package me.bobert.netneutrality.http.server;
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import io.javalin.Javalin; import io.javalin.config.RoutesConfig;
import io.javalin.http.Context; import io.javalin.http.Context;
import io.javalin.http.NotFoundResponse; import io.javalin.http.NotFoundResponse;
import io.javalin.http.ServiceUnavailableResponse; import io.javalin.http.ServiceUnavailableResponse;
@@ -18,27 +18,27 @@ import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* Registers the read-only {@code /guilds/*} endpoints on a {@link Javalin} instance. * Registers the read-only {@code /guilds/*} endpoints on a {@link RoutesConfig} instance.
*/ */
public final class GuildRoutes { public final class GuildRoutes {
private GuildRoutes() { private GuildRoutes() {
} }
public static void register(Javalin app, Supplier<JDA> jdaSupplier) { public static void register(RoutesConfig routes, Supplier<JDA> jdaSupplier) {
app.get("/guilds/owner", ctx -> ctx.json( routes.get("/guilds/owner", ctx -> ctx.json(
jda(jdaSupplier).getGuilds().stream() jda(jdaSupplier).getGuilds().stream()
.map(guild -> ordered("guild_id", guild.getId(), "owner_id", guild.getOwnerId())) .map(guild -> ordered("guild_id", guild.getId(), "owner_id", guild.getOwnerId()))
.toList() .toList()
)); ));
app.get("/guilds/channels/{guildId}", ctx -> ctx.json( routes.get("/guilds/channels/{guildId}", ctx -> ctx.json(
guild(jdaSupplier, ctx).getTextChannels().stream() guild(jdaSupplier, ctx).getTextChannels().stream()
.map(channel -> ordered("channel_id", channel.getId(), "channel_name", channel.getName())) .map(channel -> ordered("channel_id", channel.getId(), "channel_name", channel.getName()))
.toList() .toList()
)); ));
app.get("/guilds/roles/{guildId}", ctx -> ctx.json( routes.get("/guilds/roles/{guildId}", ctx -> ctx.json(
guild(jdaSupplier, ctx).getRoles().stream() guild(jdaSupplier, ctx).getRoles().stream()
.map(role -> ordered("channel_id", role.getId(), "channel_name", role.getName())) .map(role -> ordered("channel_id", role.getId(), "channel_name", role.getName()))
.toList() .toList()
@@ -55,25 +55,26 @@ public class WebApi implements Lifecycle {
int port = Integer.parseInt(settings.get("NETNEUTRALITY_API_PORT", "9000")); int port = Integer.parseInt(settings.get("NETNEUTRALITY_API_PORT", "9000"));
logger.info("Starting web server..."); logger.info("Starting web server...");
// Javalin 7 requires routes, exception and error handlers to be registered upfront.
app = Javalin.create(config -> { app = Javalin.create(config -> {
config.jsonMapper(new GsonJsonMapper()); config.jsonMapper(new GsonJsonMapper());
config.showJavalinBanner = false; config.startup.showJavalinBanner = false;
});
app.get("/", ctx -> ctx.html(LIVENESS_HTML)); config.routes.get("/", ctx -> ctx.html(LIVENESS_HTML));
GuildRoutes.register(app, jdaSupplier); GuildRoutes.register(config.routes, jdaSupplier);
ActionRoutes.register(app, jdaSupplier, guildServices, shutdownHook); ActionRoutes.register(config.routes, jdaSupplier, guildServices, shutdownHook);
app.exception(HttpResponseException.class, (e, ctx) -> config.routes.exception(HttpResponseException.class, (e, ctx) ->
ctx.status(e.getStatus()).json(Map.of("status", "error", "message", e.getMessage())) ctx.status(e.getStatus()).json(Map.of("status", "error", "message", e.getMessage()))
); );
app.exception(Exception.class, (e, ctx) -> { config.routes.exception(Exception.class, (e, ctx) -> {
logger.error("Unhandled error while serving [{}]", ctx.path(), e); logger.error("Unhandled error while serving [{}]", ctx.path(), e);
ctx.status(500).json(Map.of("status", "error")); ctx.status(500).json(Map.of("status", "error"));
}); });
app.error(404, ctx -> ctx.json(Map.of("status", "error", "message", "Not found"))); config.routes.error(404, ctx -> ctx.json(Map.of("status", "error", "message", "Not found")));
});
app.start(port); app.start(port);
logger.info("Web server started on port [{}]", port); logger.info("Web server started on port [{}]", port);
@@ -26,9 +26,11 @@ class WebModuleTest {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
server = Javalin.create(config -> config.showJavalinBanner = false); server = Javalin.create(config -> {
server.get("/counter", ctx -> ctx.result("{\"hits\":" + hits.incrementAndGet() + "}")); config.startup.showJavalinBanner = false;
server.post("/counter", ctx -> ctx.result("{\"hits\":" + hits.incrementAndGet() + "}")); config.routes.get("/counter", ctx -> ctx.result("{\"hits\":" + hits.incrementAndGet() + "}"));
config.routes.post("/counter", ctx -> ctx.result("{\"hits\":" + hits.incrementAndGet() + "}"));
});
server.start(0); server.start(0);
port = server.port(); port = server.port();
} }