upload-file-node-js-express-rest-api-feature-image

Node.js Express File Upload Rest API example using Multer

In this tutorial, I will show you how to upload file with Node.js Express Rest APIs to/from a static folder using Multer (with file size limit).

This Node.js App works with:
Angular Client
Vue Client / Vuetify Client
React Client / React Hooks Client

Related Posts:
How to upload multiple files in Node.js
Upload/store images in MySQL using Node.js, Express & Multer
How to upload/store images in MongoDB using Node.js, Express & Multer
Node.js Rest APIs example with Express, Sequelize & MySQL


Node.js Express Rest APIs for uploading Files

Our Node.js Application will provide APIs for:

  • uploading File to a static folder in the Server (restrict file size: 2MB)
  • downloading File from server with the link
  • getting list of Files’ information (file name & url)

This is the static folder that stores all uploaded files:

upload-file-node-js-express-rest-api-file-upload-folder

If we get list of files, the Node.js Rest Apis will return:

upload-file-node-js-express-rest-api-file-upload-list-response

Each item in the response array has a url that you can use for downloading the file.

These are APIs to be exported:

MethodsUrlsActions
POST/uploadupload a File
GET/filesget List of Files (name & url)
GET/files/[filename]download a File

Technology

  • express 4.17.1
  • multer 1.4.2
  • cors 2.8.5

Project Structure

This is the project directory that we’re gonna build:

upload-file-node-js-express-rest-api-file-upload-project-structure

resources/static/assets/uploads: folder for storing uploaded files.
middleware/upload.js: initializes Multer Storage engine and defines middleware function to save uploaded files in uploads folder.
file.controller.js exports Rest APIs: POST a file, GET all files’ information, download a File with url.
routes/index.js: defines routes for endpoints that is called from HTTP Client, use controller to handle requests.
server.js: initializes routes, runs Express app.

Setup Node.js Express File Upload project

Open command prompt, change current directory to the root folder of our project.
Install Express, Multer, CORS modules with the following command:

npm install express multer cors

The package.json file will look like this:

{
  "name": "node-js-express-upload-download-files",
  "version": "1.0.0",
  "description": "Node.js Express Rest APis to Upload/Download Files",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "node js",
    "upload",
    "download",
    "file",
    "multipart",
    "rest api",
    "express"
  ],
  "author": "bezkoder",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "multer": "^1.4.2"
  }
}

Create middleware for file upload

The middleware will use Multer for handling multipart/form-data along with uploading files.

Inside middleware folder, create upload.js file:

const util = require("util");
const multer = require("multer");
const maxSize = 2 * 1024 * 1024;

let storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, __basedir + "/resources/static/assets/uploads/");
  },
  filename: (req, file, cb) => {
    console.log(file.originalname);
    cb(null, file.originalname);
  },
});

let uploadFile = multer({
  storage: storage,
  limits: { fileSize: maxSize },
}).single("file");

let uploadFileMiddleware = util.promisify(uploadFile);
module.exports = uploadFileMiddleware;

In the code above, we’ve done these steps:
– First, we import multer module.
– Next, we configure multer to use Disk Storage engine.

You can see that we have two options here:
destination determines folder to store the uploaded files.
filename determines the name of the file inside the destination folder.

util.promisify() makes the exported middleware object can be used with async-await.

Restrict file size with Multer

With the new multer API. We can add limits: { fileSize: maxSize } to the object passed to multer() to restrict file size.

let storage = multer.diskStorage(...);
const maxSize = 2 * 1024 * 1024;

let uploadFile = multer({
  storage: storage,
  limits: { fileSize: maxSize }
}).single("file");

Create Controller for file upload/download

In controller folder, create file.controller.js:

– For File Upload method, we will export upload() function that:

  • use middleware function for file upload
  • catch Multer error (in middleware function)
  • return response with message

– For File Information and Download:

  • getListFiles(): read all files in uploads folder, return list of files’ informationn (name, url)
  • download(): receives file name as input parameter, then uses Express res.download API to transfer the file at path (directory + file name) as an ‘attachment’.
const uploadFile = require("../middleware/upload");

const upload = async (req, res) => {
  try {
    await uploadFile(req, res);

    if (req.file == undefined) {
      return res.status(400).send({ message: "Please upload a file!" });
    }

    res.status(200).send({
      message: "Uploaded the file successfully: " + req.file.originalname,
    });
  } catch (err) {
    res.status(500).send({
      message: `Could not upload the file: ${req.file.originalname}. ${err}`,
    });
  }
};

const getListFiles = (req, res) => {
  const directoryPath = __basedir + "/resources/static/assets/uploads/";

  fs.readdir(directoryPath, function (err, files) {
    if (err) {
      res.status(500).send({
        message: "Unable to scan files!",
      });
    }

    let fileInfos = [];

    files.forEach((file) => {
      fileInfos.push({
        name: file,
        url: baseUrl + file,
      });
    });

    res.status(200).send(fileInfos);
  });
};

const download = (req, res) => {
  const fileName = req.params.name;
  const directoryPath = __basedir + "/resources/static/assets/uploads/";

  res.download(directoryPath + fileName, fileName, (err) => {
    if (err) {
      res.status(500).send({
        message: "Could not download the file. " + err,
      });
    }
  });
};

module.exports = {
  upload,
  getListFiles,
  download,
};

– We call middleware function uploadFile() first.
– If the HTTP request doesn’t include a file, send 400 status in the response.
– We also catch the error and send 500 status with error message.

So, how to handle the case in that user uploads the file exceeding size limitation?

Handle Multer file size limit error

We can handle the error by checking error code (LIMIT_FILE_SIZE) in the catch() block:

const upload = async (req, res) => {
  try {
    await uploadFile(req, res);
    ...
  } catch (err) {
    if (err.code == "LIMIT_FILE_SIZE") {
      return res.status(500).send({
        message: "File size cannot be larger than 2MB!",
      });
    }

    res.status(500).send({
      message: `Could not upload the file: ${req.file.originalname}. ${err}`,
    });
  }
};

Define Route for uploading file

When a client sends HTTP requests, we need to determine how the server will response by setting up the routes.

There are 3 routes with corresponding controller methods:

  • POST /upload: upload()
  • GET /files: getListFiles()
  • GET /files/[fileName]: download()

Create index.js file inside routes folder with content like this:

const express = require("express");
const router = express.Router();
const controller = require("../controller/file.controller");

let routes = (app) => {
  router.post("/upload", controller.upload);
  router.get("/files", controller.getListFiles);
  router.get("/files/:name", controller.download);

  app.use(router);
};

module.exports = routes;

You can see that we use controller from file.controller.js.

Create Express app server

Finally, we create an Express server in server.js:

const cors = require("cors");
const express = require("express");
const app = express();

global.__basedir = __dirname;

var corsOptions = {
  origin: "http://localhost:8081"
};

app.use(cors(corsOptions));

const initRoutes = require("./src/routes");

app.use(express.urlencoded({ extended: true }));
initRoutes(app);

let port = 8080;
app.listen(port, () => {
  console.log(`Running at localhost:${port}`);
});

What we do are:
– import express and cors modules:

  • Express is for building the Rest apis
  • cors provides Express middleware to enable CORS with various options.

– create an Express app, then add cors middlewares using app.use() method. Notice that we set origin: http://localhost:8081.
– listen on port 8080 for incoming requests.

Run & Test

First we need to create uploads folder with the path resources/static/assets.
On the project root folder, run this command: node server.js.

Let’s use Postman to make HTTP POST request with a file.

upload-file-node-js-express-rest-api-file-upload

– Upload a file with size larger than max file size (2MB):

upload-file-node-js-express-rest-api-file-upload-limit-size

– Check uploads folder after uploading several files:

upload-file-node-js-express-rest-api-file-upload-folder

– Retrieve list of Files’ information:

upload-file-node-js-express-rest-api-file-upload-list-response

– Now you can download any file from one of the paths above.
For example: http://localhost:8080/files/bezkoder.png.

Conclusion

Today we’ve learned how to create Node.js Express Rest API to upload file into static folder using Multer for middleware handling multipart file. You also know how to restrict file size and catch Multer file size limit error.

Following tutorials explain how to build Front-end Apps to work with our Node.js Express Server:
Angular Client
Vue Client / Vuetify Client
React Client / React Hooks Client

For multiple Files at once:
How to upload multiple files in Node.js

You can also know way to upload an Excel file and store the content in MySQL database with the post:
Node.js: Upload/Import Excel file data into Database

If you want to upload images into database, you can find instructions at:
Upload/store images in MySQL using Node.js, Express & Multer
How to upload/store images in MongoDB using Node.js, Express & Multer

Happy Learning! See you again.

Further Reading

Source Code

You can find the complete source code for this tutorial on Github.

Leave a Reply

Your email address will not be published. Required fields are marked *