Skip to content

WebSocket

Mockifyr accepts WebSocket connections and replies to inbound messages from message mappings — a trigger that matches the message body, and one or more send actions whose payload is templated.

Connecting

WebSocket upgrades are accepted on any path, by a middleware at the front of the pipeline — before mock serving. There is nothing to configure and no path to register; ws://localhost:8080/anything connects.

The tenant comes from the X-Mockifyr-Tenant header on the upgrade request, as everywhere else — see multi-tenancy.

Registering a message mapping

Terminal window
curl -X POST http://localhost:8080/__admin/message-mappings \
-H 'X-Mockifyr-Tenant: team-payments' \
-d '{
"trigger": { "message": { "body": { "equalTo": "ping" } } },
"actions": [
{ "type": "send", "message": { "body": { "data": "pong" } } }
]
}'

201 with {"id": "…"} on success. Malformed JSON, or a well-formed document with a wrong-typed field, returns 422.

Every inbound message is matched against every mapping of the tenant, and each matching mapping’s actions fire — matching is not first-wins the way stub matching is.

Triggers

triggerFires on
{ "message": { "body": { …matcher… } } }An inbound message whose body the matcher accepts
{ "type": "connection" }Connect time — the actions are sent once, unsolicited, as soon as a client connects
Absent trigger bodyEvery inbound message

The message trigger reuses the standard body value-matcher setequalTo, matches, contains, equalToJson, matchesJsonPath and the rest all work exactly as in request matching.

{
"trigger": { "message": { "body": { "matchesJsonPath": "$.subscribe" } } },
"actions": [
{ "type": "send", "message": { "body": { "data": "{\"ack\":true}" } } }
]
}

Connection-triggered mappings are excluded from the per-message loop, so a connect-time mapping never also fires in response to traffic.

Send actions

A send action’s message.body carries either data or filePath.

data — an inline template

The payload renders through the same Handlebars engine and helpers as response templating, with the inbound message exposed as {{message.body}} at the template root.

{
"trigger": { "message": { "body": { "matchesJsonPath": "$.id" } } },
"actions": [
{
"type": "send",
"message": { "body": { "data": "Echo {{jsonPath message.body '$.id'}} at {{now}}" } }
}
]
}

For a connect-time mapping there is no inbound message, so templates render against an empty body.

filePath — a file from __files

{ "type": "send", "message": { "body": { "filePath": "welcome.json" } } }

The name resolves under <root-dir>/__files, WireMock’s convention — see persistence.

Broadcasting

A send action’s channelTarget defaults to the originating channel. Setting it to anything other than originating broadcasts the message to all of the tenant’s open channels.

{
"type": "send",
"channelTarget": { "type": "broadcast" },
"message": { "body": { "data": "someone said {{message.body}}" } }
}

Server-initiated push

To send a message that no client asked for, push it through the admin API. It goes to every open channel of the tenant.

Terminal window
curl -X POST http://localhost:8080/__admin/channels/send \
-H 'X-Mockifyr-Tenant: team-payments' \
-d '{"message":{"body":{"data":"deploy finished"}}}'

A body missing message.body.data, or with a non-string data, returns 422.

Not supported

FeatureStatus
Per-path or per-pattern channelTarget targetingNot implemented — a broadcast reaches all of the tenant’s channels
Binary framesNot implemented — text only
Listing message mappingsNot implemented — registration is write-only
Resetting message mappingsNot implemented — restart the host to clear them

Because mappings can be neither listed nor reset, treat registration as append-only for the lifetime of the process. Registering the same trigger twice means both mappings fire.