In this article I will show how to use MessagePack to stream binary responses to a Svelte application from a .Net Core backend.
First of all, what is MessagePack?
Most web applications rely on json as the serialization format when talking to backend apis. The main difference between json and MessagePack is that MessagePack is a binary format that tends to lead to smaller responses than the text based json format. However as we will see later in the article, this isn’t always the case.
For the purposes of this article I have created simple Svelte application for rendering a list of items fetched from a .Net Core api.
Let’s start by looking at the .Net Core Api.
First we will look at the Controller
As you can see, this is a standard .Net controller with a simple object model for describing a friend with a phone number, address, etc.
Next we will look at the required middleware in Startup.cs to enable MessagePack.
All we have to do is add a pair of new output and input formatters to wire up support for MessagePack in our api. These new formatters are added to the default set of formatters, which already includes json.
One thing I really like about the design of .Net Core apis is that everything is driven by content negotiation. Instead of hard coding a format in the controller, we instead trigger the appropriate formatter based on content headers in the request. This means the same controller method from the previous code sample will support both json and MessagePack without any code changes. Just send a request with content type application/json if you prefer json. All you need to do to change the format to MessagePack is pass application/x-msgpack.
I have included the complete Svelte component below:
Because MessagePack offers a more compact format than standard json you will see a difference in payload size between the two formats. For small results the difference is negligible, but as the size increases you start to notice a difference.
At 1000 response items the difference in size is 495kb vs. 576kb in favor of MessagePack.
This is a difference of 81k, which is substantial, but this is pre compression. What happens if we add content compression to the api response?
In my experiment I observed that Gzip or Brotli compression would both completely remove the previous gain from the more compact MessagePack binary format. I even saw a few cases where json weighed in slightly smaller than MessagePack. From this I conclude that there is no benefit from switching from json to MessagePack for payload size alone, unless of course your web server is unable to do on the fly content compression.
Streaming is where you really start to see benefits from MessagePack. Unlike json, MessagePack supports streaming deserialization, which means we don’t have to wait for the entire api payload to come back from the server. As a result we can implement a streaming UI where we display the records as we receive them.
In my next experiment I am returning a list of 100k items, a dataset that adds up to more than 20MB worth of data after compression. On a throttled 3G connection it takes about 1.9 minutes to receive the entire payload. However since I can stream out results as I receive them, the UI is quite responsive. For every chunk received from the streaming api I am updating the Svelte UI to display the latest 20 records.
The source is available on Github in case you are interested in checking out.