Handling binary messages
Most PartyKit examples you see assume WebSocket messages are strings, and more specifically, JSON strings:
Similarly, you’ll often see the server responding with stringified JSON:
These examples are simplified, because in reality, both incoming and outgoing messages can be either strings or generic raw binary data buffers:
Why ArrayBuffers?
Strings are convenient, but they are not a good format for representing non-textual data, such as images, video, WASM bundles, and others. In fact, in JavaScript programs we often use Base64
encode binary data in order to coerce it into a string. This approach is both slow and consumes a lot of memory and network bandwidth.
Even when handling textual data, strings can be inefficient. These days, most web servers compress HTTP responses using compression algorithms like gzip
. However, WebSocket messages are not compressed by default. This means that if you are sending over large amounts of textual data (for example large JSON structures), you may be wasting a lot of bytes.
ArrayBuffers allow you to represent data as low-level arrays of binary data: 0
s and 1
s. This gives you the flexibility to send any data, and represent, encode, and compress it in any format.
Binary encoding JavaScript objects using MessagePack
When it comes to encoding your data in a binary format, there is no one-size-fits-all approach. Depending on the shape of your data, you will find that different binary encodings provide different benefits and trade-offs.
In this example, we’ll use the MessagePack format and the msgpackr
library to pack (encode) and unpack (decode) our objects to a binary format.
Encoding and decoding binary data on the server
At its simplest, MessagePack is a drop-in replacement for JSON:
Decoding binary data on the client
On the client, you can also use the same library to unpack server responses:
Measure before you pack
MessagePack is easy to use, but that alone doesn’t necessarily make it a good idea.
We chose the msgpackr
implementation for this guide because it’s fast. However, given that JSON.parse
and JSON.stringify
are built natively into the JavaScript runtime, they are very fast too. This means that you may not realize the type of performance gains you want.
Additionally, if you use the msgpackr
library on the client size, you are adding nearly 10 kB of code to you JavaScript bundle.
Choosing to use a binary encoding is a trade-off, but typically, generic binary encodings make sense when you are sending large data payloads. For smaller messages, they may not make sense.
Mix both JSON and MessagePack encodings
Because you are in full control of the server and client, you can make assumptions about the data encoding based on the message
format.
You could for example assume, that when a message is of type string
, it’s going to be JSON, and when it’s a binary blob, it’s encoded with MessagePack:
And do the same on the client:
With this approach, you can use MessagePack for large messages, such as syncing over large sets of data at once, and still use JSON for smaller messages.
Validating binary data
Encoding libraries like MessagePack will usually validate that the data conforms to a format, but they are agnostic to the content of the message.
To learn about validating data against a schema, read our guide on validating client inputs guide.