Node.js: Unzip Async Await

Unzip a .zip file in an asynchronous Node.js context.

Mar 14, 2021

#javascript #nodejs #webdev #programming

Photo by Florian Steciuk on Unsplash


I am developing a new feature of DeckDeckGo for which I have to unzip a data in Firebase Functions.

It took more time than expected to code such a Node.js function, that’s why I am sharing this solution, hoping it might help you some day too 😇.


Unzipper

Node.js provides a compression module Zlib but, it does not support ZIP files. Luckily, we can use the library unzipper to handle these.

npm i unzipper --save

Unzip With Async Await

My new feature reads and writes data uploaded in Firebase Storage through streams. I also develop my code with a promises (async / await) approach. Therefore, both have to coexist.

To narrow down the following example, I replaced the cloud storage with local files handled with file system streams (fs ).

The function unzip instantiates a stream on the zip data which is piped with unzipper . Each entry are iterated and piped themselves to writable outputs. Summarized: the zip is opened and each files it contains are extracted.

unzip is called in a retro compatible top await function and, that’s basically it 🥳.

const { Parse } = require("unzipper");
const { createWriteStream, createReadStream } = require("fs");

const unzip = () => {
    const stream = createReadStream("/Users/david/data.zip").pipe(Parse());

    return new Promise((resolve, reject) => {
        stream.on("entry", (entry) => {
            const writeStream = createWriteStream(`/Users/david/${entry.path}`);
            return entry.pipe(writeStream);
        });
        stream.on("finish", () => resolve());
        stream.on("error", (error) => reject(error));
    });
};

(async () => {
    try {
        await unzip();
    } catch (err) {
        console.error(err);
    }
})();

Read To String With Async Await

I had to read files with streams too. Consequently and cherry on top, here is how I integrated these in my code.

const { createReadStream } = require("fs");

const read = () => {
    const stream = createReadStream("/Users/david/meta.json");

    return new Promise((resolve, reject) => {
        let data = "";

        stream.on("data", (chunk) => (data += chunk));
        stream.on("end", () => resolve(data));
        stream.on("error", (error) => reject(error));
    });
};

(async () => {
    try {
        const meta = await read();

        console.log({ meta });
    } catch (err) {
        console.error(err);
    }
})();

It follows the same approach as previously and read the file content to an in memory string.


Summary

Coding is like a box of chocolates. You never know what you’re gonna get. Sometimes it should be quick, it takes time. Sometimes it should take so much time but, it goes fast — For-dev-rest Gump

To infinity and beyond!

David