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