Introduction
What is hoppity?
Section titled “What is hoppity?”Hoppity is a contract-driven RabbitMQ topology builder for Node.js microservices, built on top of Rascal. You declare domain contracts (events, commands, RPC) using Zod schemas, register handlers, and Hoppity derives all the Rascal topology automatically — exchanges, queues, bindings, publications, and subscriptions.
The Problem
Section titled “The Problem”Rascal gives you a powerful, configuration-driven way to manage RabbitMQ topologies. But as your microservice estate grows, you end up with:
- Repeated boilerplate across services (the same exchange patterns, the same retry configurations)
- Topology config objects that balloon into hundreds of lines
- String-literal coupling between services — rename a queue and watch everything break at runtime instead of compile time
- No clean way to share message schemas between producers and consumers
The Solution
Section titled “The Solution”Hoppity introduces domain contracts as the single source of truth. You define what your service handles and what it sends. The topology is derived mechanically from those declarations.
No topology files. No manual exchange/queue/binding declarations. The contracts carry the naming conventions, and deriveTopology generates all the Rascal config.
Packages
Section titled “Packages”| Package | Purpose |
|---|---|
@apogeelabs/hoppity | Core — contracts, handlers, topology derivation, builder, broker wiring, RPC, delayed delivery |
@apogeelabs/hoppity-open-telemetry | OpenTelemetry tracing and metrics interceptors |
How the Pipeline Works
Section titled “How the Pipeline Works”When you call .build(), seven phases execute in order:
-
Topology derivation —
deriveTopology()generates all exchanges, queues, bindings, publications, and subscriptions from the handler declarations and publish contracts. -
Topology merge —
mergeTopology()combines any optional rawBrokerConfigwith the derived topology. Raw config is the base; derived topology layers on top. -
Middleware pipeline — Each middleware runs sequentially, receiving the complete merged topology and shared
MiddlewareContext. Returns modified topology and an optionalonBrokerCreatedcallback. -
Broker creation —
BrokerAsPromised.create(finalTopology)via Rascal. -
Handler wiring — Event, command, and RPC handlers are subscribed to their derived queues.
-
Outbound wiring —
publishEvent,sendCommand,request, andcancelRequestare attached to the broker. -
Callback execution — Each middleware’s
onBrokerCreatedcallback runs against the fully-wired broker. If any callback throws, the broker is shut down before the error propagates.