WebSocket Support Beta #2010
Replies: 11 comments 22 replies
-
Allow preventing connection-level actionsRight now, if a handler has some action on the connection event, like greeting any connected client, it's impossible to opt-out from that behavior completely: api.on('connection', ({ client }) => client.send('hello'))
server.use(
api.on('connection', ({ client }) => ???)
) No matter what you do in the override handler, the connected client will always receive api.on('connection', (event) => {
event.client.send('hello')
})
server.use(
api.on('connection', (event) => {
event.stopImmediatePropagation()
event.client.send('howdy')
})
)
Downsides:
|
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
Routing events through Service WorkerAll data sent by WebSocket is transferable: string, blob, arraybuffer. We can route the connection through the Service Worker. Here's why we should consider doing so:
There are some minor downsides to this too. Mainly, the browser and Node.js handling of WebSocket events will be different internally. This doesn't affect the developer's experience in a negative way. If anything, it may improve DX by providing a consistent
|
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
-
Hi @kettanaito I was looking at and looking forward to the websocket support. Is it possible to clarify what is meant with "MSW will only support mocking WebSocket connections implemented via the WHATWG WebSocket API"? How can I find out if what is running via websocket is supported by MSW? Specifically, I'm trying to get it to work with https://github.com/enisdenjo/graphql-ws/, but Would be cool to have a bit more info about this. And possibly a debug mode where MSW intercepts all Websocket connections and shows if it can work with them? Idk if this is even possible, just a thought. |
Beta Was this translation helpful? Give feedback.
-
Add loggingWould be great to add logging for outgoing and incoming events like what we have for HTTP requests. Twice as useful given the interception takes away the observability in the Network tab. |
Beta Was this translation helpful? Give feedback.
-
Hi @kettanaito Can you add a Jest (yes, I know you are not a fan :-) ) example as well? I am wondering how you envision the handling of events within a specific jest test or group of tests. |
Beta Was this translation helpful? Give feedback.
-
Unhandled connectionsWith the introduction of a new protocol to MSW, I consider adding different protocol-based options to the server.listen({
http: {
onUnhandledRequest({ request, print }) {}
},
ws: {
onUnhandledConnection({ client, print }) {}
}
}) This can help greatly to decouple the configurations for different protocols, such as mocking, debugging, handling of unhandled requests/connections. |
Beta Was this translation helpful? Give feedback.
-
Hi! Thanks for finding time to share your feedback on the WebSocket support in MSW!
Goals
The main goal behind this RFC is to gather feedback on the WebSocket interception API in MSW and give the beta release a try once it's out.
Before you begin
Important
MSW will only support mocking WebSocket connections implemented via the WHATWG WebSocket API. We are committed to the standard-driven API mocking, and that includes WebSockets! The
WebSocket
API is globally available in the browser, and it's also coming to Node.js this year (already available as an experimentalWebSocket
API inundici
).Getting started
Install the
msw@next
package to get the work-in-progressws
API:ws
APIGeneral statements
server.connect()
.event.preventDefault()
in the relevant server event listener.MSW API
In the context of MSW, I propose the following API to intercept WebSocket connections:
ws.url()
method and provide it a valid WebSocket connection URL (using with thews:
/wss:
scheme).ws.url()
method will be an EventTarget-like object that allows you to subscribe to a single "connection" event. This mirrors theWebSocketInterceptor
public API.client
and theserver
connection representations.client
lets you intercept outgoing client events (client.on(event, listener)
) and mock incoming server events (client.send(data)
).server
lets you establish the actual server connection (server.connect()
), intercept incoming server events (server.on(event, listener)
), and mock outgoing client events (server.send()
).Below, see some of the use cases for the WebSocket interception.
Developing mock-first
Event patching
This is an example of combining the actual WebSocket connection and the mock to intercept the duplex communication and mock it bothways.
Closing the connection
Since the connection listener, just like the HTTP request handlers, is written from the server's perspective, you can use otherwise non-configurable status codes (see RFC6455) to close the client connection. This allows you to mock various server close scenarios.
Usage with Socket.IO
Since Socket.IO supports the
websocket
transport, you can intercept and mock Socket.IO connections. However, since Socket.IO introduces a custom protocol to encode and decode messages, you will receive the raw encoded messages if you observe the traffic using the interceptor:Operating with Socket.IO connections on the raw WebSocket level requires you to understand its protocol, which is not something you should know in order to use Socket.IO. With that in mind, I'm proposing to introduce a concept of bindings.
Here's an example of a Socket.IO binding that converts the raw WebSocket connections into a more familiar Socket.IO-like connection:
Questions
ws.url
orws.link
? I'd like to have consistency withgraphql.link
so one of them should be renamed.ws.link()
for consistency.ws
"event handlers" are self-contained, meaning that they don't follow the usual request resolution pipeline (request -> handlers list -> response). But I still wish for WebSocket logic to be placed alongside the rest of your handlers..use()
). How should these work? Once again, thews
API is self-contained. It will dispatch the "connection" event to allws
interceptors but there's no conventional event propagation here to stop to support a fallthrough behavior akin to request handlers.return
but viaevent.stopImmediatePropagation()
. This supports opting-out even from individualclient
/server
events as those share the same event instance across multiple listeners and even WebSocket event handlers.Beta Was this translation helpful? Give feedback.
All reactions