receive
Accepts the inbound POST and emits a raw Webhook@1. The only node allowed to touch the network edge.
IN PRACTICE / WEBHOOKS
A webhook endpoint is a small pipeline pretending to be a controller action.
Read the manifest
Accepts the inbound POST and emits a raw Webhook@1. The only node allowed to touch the network edge.
THE ARCHITECTURE
bloccs makes the pipeline explicit: one node owns the HTTP edge, a pure node verifies the payload, a split decides where each event goes, and the effectful sinks each declare exactly what they touch. Unknown events are dead-lettered instead of dropped, and every hop is typed and traced — so a malformed payload fails at the boundary, not three stages deep.
Where this stands today: verification, routing, persistence, dispatch and dead-lettering all run in 0.8. By design, bloccs doesn't serve HTTP itself — receive is fed by your web layer (Phoenix or any endpoint), and everything from there down is bloccs.
SOURCE OF TRUTH
The network is declared in TOML. Compile it with its referenced node manifests and bloccs checks the wiring, schemas, and capabilities before emitting a Broadway supervision tree.
mix bloccs.compile
Node implementations live in the referenced nodes/*.bloccs files.
[network]
id = "webhooks"
version = "0.1.0"
runtime = "beam"
[nodes]
receive = { use = "nodes/receive.bloccs" }
verify = { use = "nodes/verify.bloccs" }
route = { use = "nodes/route.bloccs" }
persist = { use = "nodes/persist.bloccs" }
dispatch = { use = "nodes/dispatch.bloccs" }
dlq = { use = "nodes/deadletter.bloccs" }
[[edges]]
from = "receive.received"
to = "verify.webhook"
[[edges]]
from = "verify.valid"
to = "route.webhook"
# Fan-out: a known event is both persisted and dispatched downstream.
[[edges]]
from = "route.known"
to = ["persist.event", "dispatch.event"]
[[edges]]
from = "route.unknown"
to = "dlq.event"
[expose]
in = { hook = "receive.received" }
out = { stored = "persist.stored", sent = "dispatch.sent", dead = "dlq.recorded" }
[supervision]
strategy = "rest_for_one"
max_restarts = 5
max_seconds = 60
[deploy]
concurrency = { persist = 1, dispatch = 4 }
The kind describes its role. The capability declares its reach.
Accepts the inbound POST and emits a raw Webhook@1. The only node allowed to touch the network edge.
Checks the signature and shape. Pure: same input, same verdict, no I/O — trivially testable.
Branches on event type. Known types continue; everything else is forced down the dead-letter path.
Writes the event to the store. Declares the DB capability — a stray HTTP call here won't compile.
Fans the known event downstream. Runs concurrently with persist under the supervisor.
Records unknowns instead of dropping them, so nothing silently disappears.
KEEP EXPLORING
Declare the graph. Check the contracts. Let the BEAM run it.
Read the docs{:bloccs, "~> 0.9"}
We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect