Skip to main content

Devtools Dashboard

ligero-devtools is a visual debugger for development served at /ligero/dev — a graph-centred workbench where you run a request, watch it flow through your beans, and inspect the JSON going in and out of every layer, with timings, all without a debugger, a log line, or an external tool like Postman.

Think of it as Swagger's "try it out" + a live dependency graph + a per-request tracer, in one page, shipped inside your jar (self-contained HTML, no CDN), and switched off with a single flag for production.

Running a request and watching its execution path light up the bean graph, with the JSON response below

Why it exists​

Without devtoolsWith devtools
Fire requests from curl/Postman in another windowRun any route straight from the dashboard
Read logs to guess which beans ranSee the exact path light up in the graph
Add System.out.println to see a layer's args/resultClick a node — arguments and return value are shown as JSON
Wonder how long each layer tookEvery call carries its timing; the path shows the critical route
Keep a mental model of your wiringThe dependency graph is drawn for you, coloured by stereotype

It's built on the same Beans container and layered architecture Ligero already encourages — devtools just makes them visible.

Setup​

Add the dependency (development only) and instrument your beans:

// build.gradle — never ship this to production
implementation 'com.ligeroframework:ligero-devtools:0.6.0'
Devtools devtools = Devtools.create();

Beans beans = Beans.builder()
.bind(NameRepo.class, b -> new JdbcNameRepo(b.get(DataSource.class)))
.bind(GreetService.class, b -> new DefaultGreetService(b.get(NameRepo.class)))
.instrument(devtools.recorder()) // spies interface-typed beans
.start();

Ligero app = Ligero.create();
app.beans(beans);
devtools.install(app, beans); // mounts /ligero/dev — call before app.start()
app.start(8080);

Prefer to scaffold it? The CLI wires devtools into new projects by default — opt out with --devtools false:

ligero new my-api # devtools ready at /ligero/dev
ligero new my-api --devtools false # lean app, no devtools

Open http://localhost:8080/ligero/dev.

The workbench​

The page has two zones: the bean graph on top and a request workbench below (a request list on the left, an editor / detail panel on the right).

1. Pick and run a request​

The left Requests tab lists your app's routes. Select one and the editor fills in its path parameters, query and JSON body; press Send and Ligero fires the call for you (correlated with an X-Ligero-Dev header so the trace it produces is matched back to this exact request). The response — status, timing, JSON body — appears right there.

2. Selecting shows the dependency graph; running shows the path​

Selecting a request lights up its dependency graph — every bean it can reach (controller → services → repositories) — and dims the rest. No execution path is drawn yet, because which branch runs isn't known until you send it (a service may call one repository or another depending on a validation).

Selecting a request lights up its full dependency graph without an execution path

Press Send and the actual execution path is overlaid in bold, animated, in the HTTP method's colour. A dependency that this run didn't take stays visible but is clearly not part of the execution.

3. The path is coloured by method​

The highlighted path takes the request's method colour — GET green, POST blue, PUT amber, DELETE red, PATCH purple — matching the verb badges, so a glance tells you what kind of call you're looking at.

A POST request highlighting its path in blue

4. Click a node for its per-layer detail​

Click any bean and the right panel shows, for the selected run, each of its invocations with arguments and return value as real JSON (records, beans, collections — not a toString), plus its timing, stereotype and dependencies. The whole UI has light and dark themes with a toggle.

Clicking a node reveals its arguments and JSON return value for the request, in dark theme

The History tab keeps the requests you've run (and any live traffic that arrives over SSE); click one to replay its path in the graph.

How the spying works​

  • devtools.recorder() is a BeanDecorator: beans bound as interfaces get wrapped in a JDK dynamic proxy — no bytecode generation, no agents, no reflection on your domain types beyond a small, bundled JSON serializer.
  • Beans bound as concrete classes can't be proxied; they pass through untouched and the dashboard marks them as not traceable. Bind by interface if you want them traced.
  • A middleware opens one trace per request (reusing the request-id when the request-id middleware is on, or the dashboard's correlation header), records the matched route, request inputs and the response body, and keeps the last 100 traces.
  • The devtools endpoints themselves are never traced.

Endpoints​

EndpointWhat
GET /ligero/devthe dashboard (self-contained HTML — no CDN assets)
GET /ligero/dev/api/routesregistered routes, for the "run a request" panel
GET /ligero/dev/api/graphbean graph JSON (nodes, edges, unspied list)
GET /ligero/dev/api/requestslast 100 traces, most recent first
GET /ligero/dev/api/streamSSE stream of completed traces

Production​

Never install devtools in production — it exposes the arguments and return values of your beans. Two switches:

  1. Classpath (recommended): keep the dependency out of your production build; there is zero overhead because nothing is there. With the CLI, --devtools false scaffolds a project without it.
  2. Environment: LIGERO_DEVTOOLS=false turns install() into a no-op without a code change.