FabrikFabrik
FabrikQuery Builder

Connection rules

Why the canvas refuses some edges — the structural rules, the ACI hierarchy enforced through the Class Browser, and the pipeline exception.

The canvas doesn't let you wire arbitrary graphs. Two layers of rules shape what you can build:

  • Structural rules — enforced live when you drag a connection. They're about node types (Start, Class, Filter, Post-Processor, Output), not specific ACI classes.
  • Hierarchy rules — enforced by the Class Browser when you add a class. They're about ACI classes — what can legally contain what, drawn straight from the MIM graph you loaded earlier.

Understanding where each layer lives makes the canvas's behaviour predictable instead of mysterious.

Structural rules: the full table

When you drag from one node's right handle onto another node's left handle, Fabrik consults a set of structural rules. These are hard-coded into the canvas and run before any MIM lookup.

EdgeAllowed?Notes
Start → ClassThe only way to get a class directly wired to Start via manual drag.
Class → FilterA filter takes exactly one class feed.
Class / Filter / Post-Processor → Post-ProcessorPost-processors chain freely.
Class / Filter / Post-Processor → OutputOutput terminates from any of the three.
Output → ClassPipeline edge — starts a new query stage.
Post-Processor → ClassPipeline edge — same as above.
Start → anything but ClassStart feeds only a class.
Class → Class (manual drag)Has to go through the menu's Child Class flow (see below).
Anything → StartStart has no inputs.

That's the whole structural surface. Anything not in the table is rejected — the React Flow connection line snaps back with no toast, no error, no side-effect.

Single-in, single-out (with one exception)

Outside of pipeline edges, every node has at most one incoming and one outgoing edge. The canvas enforces this on every drag. The result is a clean linear chain — not a tree, not a DAG.

The single exception is pipeline edges, covered below. A single Output (or Post-Processor) can fan out multiple pipeline edges, each feeding a distinct downstream stage.

Hierarchy rules: where the MIM comes in

Class-to-class edges exist — fvTenant → fvBD → fvSubnet is a perfectly ordinary query. The trick is that those edges aren't created by manual drag. They're created by the menu's Child Class flow, and the Class Browser dialog is what constrains the choices to a valid ACI child of the parent.

Here's what actually happens when you pick Child Class from a Class node's Add Node menu:

  1. Fabrik walks the edges backwards from the source node until it finds the nearest Class ancestor.
  2. The Class Browser opens scoped to the MIM's containment children of that ancestor — nothing else.
  3. Only classes that can legally live under the parent are visible. Picking any of them creates a valid class-to-class edge automatically.

Filter and Post-Processor nodes are passed through by this walk. If you place a Filter after fvTenant and then request Child Class from the Filter, the browser is still scoped to fvTenant's children — not the filter's (which wouldn't mean anything). This keeps the hierarchy meaningful no matter how many transform nodes you drop between classes.

The practical upshot: you can't build an impossible ACI graph because impossible relationships don't appear in the browser to begin with. If a parent→child combination isn't in the MIM, it's invisible — you never get the option.

Pipeline edges — the structural exception

A pipeline edge lets the results of one query stage feed the filters of the next. It's the one case where an Output (or Post-Processor) can connect forward into a new Class node.

Valid pipeline edges:

  • Source: Output or Post-Processor.
  • Target: Class.

Two pieces of metadata ride along with a pipeline edge:

  • extractField — which property to pluck from each result row. Default: dn.
  • injectAs — how to feed it into the next stage's class filter. Default: filter_values (turned into an in filter on the downstream class).

Pipeline edges also relax the single-outgoing-edge rule on their source. One Output can fan out to several pipeline stages — handy when you want to run multiple follow-up queries against the same set of results.

On the canvas, pipeline edges render differently from regular containment edges (dashed line, label showing the extract field). The full mechanics live on the Pipelines page.

Reconnecting an existing edge

To move an edge, drag its middle onto a different target. React Flow handles the gesture natively, and the same structural rules apply — an invalid drop leaves the edge unchanged or drops it entirely.

This is the cleanest way to insert a node between two existing ones: drag the edge through the new node, or delete-and-redraw.

Locked canvas

When the canvas is locked (the Lock toggle in the bottom zoom bar — see Canvas basics), drag-to-connect is disabled. The validator never even runs — connections simply can't start. Unlock to edit again.

Why rules fail silently

The canvas is deliberately quiet about rejections:

  • Manual drag. An invalid connection attempt just doesn't catch — the line snaps back. No error, no toast. The rationale is that a rejected drag is self-evidently rejected, and noise during exploration is more annoying than helpful.
  • Menu + browser. If a parent class has no valid children, the Class Browser shows an empty state rather than an explicit refusal. That usually means the MIM is incomplete for that class, or the class is genuinely a leaf.

Troubleshooting

A handful of patterns come up often:

  • "I can't draw an edge between two class nodes." That's correct — class-to-class via manual drag isn't allowed. Delete the target class and re-add it through the source class's menu as a Child Class. The browser will scope correctly and draw the edge for you.
  • "The Class Browser is empty when I pick Child Class." The parent class has no containment children in the loaded MIM. Either your MIM doesn't include those relationships (install a matching version via MIM Management) or the class is a leaf that can't contain anything.
  • "An edge disappeared after I tried to rewire it." Dropping onto an invalid target silently drops the edge — the old one is already removed by the reconnect. Drag from the source again to rebuild it.
  • "Run is disabled even though everything looks wired." The graph is missing an Output, or there's a class node with no successor. The canvas won't warn you — scan for stranded nodes.

Rules understood. The next page — Filters — is about shaping what APIC returns using its own filter grammar.