Sending Messages via Admin API
In addition to stub-triggered responses, WireMock allows you to proactively send messages to connected clients via the Admin API. This is useful for simulating server-initiated events like notifications, broadcasts, or push updates.
Sending to Channels
Section titled “Sending to Channels”Send to Matching Channels
Section titled “Send to Matching Channels”Send a message to all WebSocket channels matching a request pattern:
import static com.github.tomakehurst.wiremock.client.WireMock.*;import static com.github.tomakehurst.wiremock.matching.RequestPatternBuilder.newRequestPattern;
// Send to all channels on a specific pathSendChannelMessageResult result = wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern().withUrl("/notifications").build(), new StringEntityDefinition("Server notification!"));
System.out.println("Sent to " + result.getSentCount() + " channels");curl -X POST http://localhost:8080/__admin/channels/send \ -H "Content-Type: application/json" \ -d '{ "type": "websocket", "initiatingRequest": { "url": "/notifications" }, "message": { "body": { "data": "Server notification!" } } }'Send to All Channels on a Path Pattern
Section titled “Send to All Channels on a Path Pattern”// Broadcast to all channels matching a URL patternSendChannelMessageResult result = wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern() .withUrl(urlPathMatching("/users/.*/updates")) .build(), new StringEntityDefinition("{\"type\": \"refresh\"}"));curl -X POST http://localhost:8080/__admin/channels/send \ -H "Content-Type: application/json" \ -d '{ "type": "websocket", "initiatingRequest": { "urlPathPattern": "/users/.*/updates" }, "message": { "body": { "data": "{\"type\": \"refresh\"}" } } }'Send Based on Headers
Section titled “Send Based on Headers”Target channels based on the headers of the initiating request:
// Send to authenticated user channelsSendChannelMessageResult result = wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern() .withUrl("/ws") .withHeader("X-User-ID", matching("admin-.*")) .build(), new StringEntityDefinition("Admin broadcast"));curl -X POST http://localhost:8080/__admin/channels/send \ -H "Content-Type: application/json" \ -d '{ "type": "websocket", "initiatingRequest": { "url": "/ws", "headers": { "X-User-ID": { "matches": "admin-.*" } } }, "message": { "body": { "data": "Admin broadcast" } } }'Listing Active Channels
Section titled “Listing Active Channels”Before sending messages, you may want to see which channels are currently connected:
ListMessageChannelsResult result = listAllMessageChannels();
for (MessageChannel channel : result.getChannels()) { System.out.println("Channel ID: " + channel.getId()); System.out.println("Type: " + channel.getType()); System.out.println("Path: " + channel.getInitiatingRequest().getUrl());}curl http://localhost:8080/__admin/channelsResponse:
{ "channels": [ { "id": "abc123", "type": "websocket", "initiatingRequest": { "url": "/notifications", "method": "GET", "headers": { "Upgrade": "websocket", "Connection": "Upgrade" } } }, { "id": "def456", "type": "websocket", "initiatingRequest": { "url": "/users/42/updates", "method": "GET" } } ]}Message Content Options
Section titled “Message Content Options”Plain Text
Section titled “Plain Text”wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern().withUrl("/chat").build(), new StringEntityDefinition("Hello, World!"));{ "message": { "body": { "data": "Hello, World!" } }}JSON Content
Section titled “JSON Content”String jsonMessage = """ { "type": "notification", "payload": { "title": "New message", "content": "You have a new message" } } """;
wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern().withUrl("/notifications").build(), new StringEntityDefinition(jsonMessage));{ "message": { "body": { "data": "{\"type\": \"notification\", \"payload\": {\"title\": \"New message\", \"content\": \"You have a new message\"}}" } }}From File
Section titled “From File”SendMessageActionBuilder builder = sendMessage() .withBodyFromFile("__files/notification.json");
// Use in a stubmessageStubFor( message() .triggeredByHttpRequest( newRequestPattern().withMethod(POST).withUrl("/trigger")) .willTriggerActions( builder.onChannelsMatching( newRequestPattern().withUrl("/notifications"))));{ "message": { "body": { "filePath": "__files/notification.json" } }}Use Cases
Section titled “Use Cases”Server-Initiated Notifications
Section titled “Server-Initiated Notifications”Simulate a server pushing notifications to clients:
@Testvoid serverPushNotification() { // Connect a client WebSocketClient client = new WebSocketClient(); client.connect("ws://localhost:" + wireMockServer.port() + "/notifications");
// Wait for connection await().until(client::isConnected);
// Server sends a notification wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern().withUrl("/notifications").build(), new StringEntityDefinition("{\"alert\": \"New data available\"}"));
// Verify client received the message await().until(() -> client.getMessages().contains("{\"alert\": \"New data available\"}"));}Broadcasting to Multiple Clients
Section titled “Broadcasting to Multiple Clients”Send a message to all connected clients:
@Testvoid broadcastToAllClients() { // Connect multiple clients WebSocketClient client1 = new WebSocketClient(); WebSocketClient client2 = new WebSocketClient(); WebSocketClient client3 = new WebSocketClient();
client1.connect("ws://localhost:" + wm.port() + "/broadcast/user1"); client2.connect("ws://localhost:" + wm.port() + "/broadcast/user2"); client3.connect("ws://localhost:" + wm.port() + "/broadcast/user3");
// Wait for all connections await().until(() -> client1.isConnected() && client2.isConnected() && client3.isConnected());
// Broadcast to all /broadcast/* channels SendChannelMessageResult result = wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern() .withUrl(urlPathMatching("/broadcast/.*")) .build(), new StringEntityDefinition("System announcement"));
assertThat(result.getSentCount(), is(3));
// Verify all clients received the message await().until(() -> client1.getMessages().contains("System announcement") && client2.getMessages().contains("System announcement") && client3.getMessages().contains("System announcement"));}Simulating Real-Time Updates
Section titled “Simulating Real-Time Updates”Simulate periodic server updates:
@Testvoid simulateStockPriceUpdates() { WebSocketClient client = new WebSocketClient(); client.connect("ws://localhost:" + wm.port() + "/stocks/AAPL");
await().until(client::isConnected);
// Simulate multiple price updates for (int i = 0; i < 5; i++) { String priceUpdate = String.format( "{\"symbol\": \"AAPL\", \"price\": %.2f, \"timestamp\": %d}", 150.00 + Math.random() * 10, System.currentTimeMillis());
wireMockServer.sendChannelMessage( ChannelType.WEBSOCKET, newRequestPattern().withUrl("/stocks/AAPL").build(), new StringEntityDefinition(priceUpdate));
Thread.sleep(100); // Simulate update interval }
// Verify client received multiple updates await().until(() -> client.getMessages().size() >= 5);}HTTP-Triggered WebSocket Notifications
Section titled “HTTP-Triggered WebSocket Notifications”Use HTTP stubs to trigger WebSocket messages:
import static com.github.tomakehurst.wiremock.client.WireMock.*;import static com.github.tomakehurst.wiremock.matching.RequestPatternBuilder.newRequestPattern;
// HTTP endpoint that triggers a WebSocket notificationstubFor(post("/api/orders") .willReturn(ok("{\"orderId\": \"123\"}")));
// Message stub triggered by the HTTP requestmessageStubFor( message() .withName("Order notification") .triggeredByHttpRequest( newRequestPattern().withMethod(POST).withUrl("/api/orders")) .willTriggerActions( sendMessage("{\"type\": \"order_created\", \"orderId\": \"123\"}") .onChannelsMatching(newRequestPattern().withUrl("/notifications"))));
// Now when POST /api/orders is called, a WebSocket message is sentAdmin API Endpoints Reference
Section titled “Admin API Endpoints Reference”| Endpoint | Method | Description |
|---|---|---|
/__admin/channels | GET | List all active message channels |
/__admin/channels/send | POST | Send message to matching channels |
Send Channel Message Request Format
Section titled “Send Channel Message Request Format”{ "type": "websocket", "initiatingRequest": { "url": "/path", "urlPath": "/exact-path", "urlPattern": "/path/.*", "urlPathPattern": "/path/.*", "method": "GET", "headers": { "Header-Name": { "equalTo": "value", "matches": "pattern.*", "contains": "substring" } } }, "message": { "body": { "data": "message content", "filePath": "__files/message.json" } }}Send Channel Message Response Format
Section titled “Send Channel Message Response Format”{ "sentCount": 3}The sentCount indicates how many channels the message was sent to.