Search code examples
javascriptruby-on-railszlibpako

Sending large Data Object from Rails Backend to JavaScript Frontend with zlib


I am reviewing code I wrote a few years ago and stumbled across the following snippets that I use to send large data objects from my Ruby on Rails backend to the JavaScript frontend. I apply the zlib gem to compress and the pako library to decompress the data object.

The Ruby part for compression is quite straightforward:

Base64.encode64(Zlib::Deflate.deflate(original_data.to_json))

The hash original_data is first converted to a JSON string, compressed with zlib and then encoded to Base64 for transmission.

I derived the JavaScript part for decompression from an answer that was posted in 2015 and it is a bit more involved:

let decodedData = atob(data);
let uncompressedData = new Uint16Array(pako.inflate(new Uint8Array(decodedData.split("").map((e) => { return e.charCodeAt(0); }))));
let convertedData = ""
uncompressedData.forEach(function(element) {
  convertedData += String.fromCharCode(element);
});
let originalData = JSON.parse(convertedData);

I honestly do not fully understand what is going on there between decoding Base64 and parsing the JSON string but it works.

The test hash original_data = { key1: "foo", key2: "bar"} gives in the compressed Base64 string

eJyrVspOrTRUslJKy89X0gFxjICcpMQipVoAcckIFw==

and is successfully decompressed to Object { key1: "foo", key2: "bar" }.

I was wondering if there is a "better" way to accomplish this now in 2023 with zlib gem v2.1.1 and pako_inflate v2.1.0? Maybe it is possible to leverage some additional zlib parameters in the backend to reduce the complexity of the code in the frontend?

All my experiments so far ended with the error message "unsupported compression method".


Solution

  • I was able to rewrite my code so that it is now a bit more compact. But the basic procedure has remained the same.

    let decodedData = atob(data);
    let uncompressedData = pako.inflate(Uint8Array.from(decodedData, (code) => code.charCodeAt(0)));
    let convertedData = JSON.parse(new TextDecoder(uncompressedData).decode());