Refactoring Multer instance using Javascript Closures

Kaung Myat Lwin
3 min readJun 12, 2020
Photo by Jamie Street on Unsplash

Recently I was coding file upload using expressand multer to handle file uploads on the server side. This time the requirement for the app I’ve been working on won’t use AWS S3. The tasks I had to do in the following list are,

  • Direct file storage on the server directory.
  • File uploads from Frontend will definitely bemultipart/form-data.
  • Use multer as it is a popular library in ExpressJS community to handle file uploads as well as Form Data.
  • Our app will be divided with independent Express Router Files to handle each endpoints.
  • The files uploaded will be stored on different file paths on the disk based on the endpoints.

Configuring Express, Routers and multer was a breeze. The problem once came up when I had to declare many multerdiskStorage instances across the files for separate file paths. It was a tedious task with clear violation of DRY principle. To clearly see the problem, take a glance at the prototype code below.

You can clearly see both are almost identical. Only destination is changed. As I said above this is a violation of DRY principle. It won’t be feasible to copy + paste the multer instance every time we create a new route with file upload handlers, plus we might have additional configurations in the future (eg: a change in file naming).

Let’s fix it.

What if we could have one multer instance, and require them with minimal effort and pass it on as our regular middleware? My idea is to use it like,

const upload = require('./upload')('./file_destination');

This is where the concept of Closures come into play. Take a look at this diagram to understand the gist of how it will work with the whole application.

Application Overview (pardon my poor drawing skills)

Right. Here is how new upload.js file looks like after a refactor. Looks so simple from clustered code before, right? Keep reading and I’ll explain the technical details below.

Refactored Code

See the significant reduced codes in cats.js and dogs.js? We should always keep that simplicity!

What happened when we require('multer')('./file_destination')? This is the meat of Javascript Closures. Here is my thought process.

  • Each require always return an object, a function, array or a variable from the exported module.
  • In this case, we passed on upload function with anonymous function with dirPath parameter in upload.js.
  • The second scope of require, ('./file_destination') is passed into that anonymous function.
  • ./file_destination is then again passed into dirPath in customStore function of storage object (which returns multer.diskStorage object), enabling to utilize the variable passed from outside of its scope, finally returning with a multer instance with proper storage option once initialization is done.
  • require('multer')('./file_destination') it in the Routers and profit.

This is one simple practical use of how Closures are used. Understanding and practically using Closures are sorcery at the start but once you’ve gripped on the concepts, it becomes your weapon.

Hope you’ve enjoyed the demonstration. Thank you for reading this far!

--

--