DEV Community

Cover image for How to build NodeJS Express REST API to Upload Image using Multer(PostgreSQL)
Kafeel Ahmad (kaf shekh)
Kafeel Ahmad (kaf shekh)

Posted on

How to build NodeJS Express REST API to Upload Image using Multer(PostgreSQL)

Introduction

Image uploading — doesn’t it sound like a complex feature to implement, But let me tell you it is not. So, in this article we will build Api for uploading single and multiple images to the server using Multer.

According to the documentation,

Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files.

NOTE: Multer will not process any form which is not multipart (multipart/form-data).

Prerequisites

  • Node.js and PostgreSQL should be installed in your system and you should have good knowledge of both.
  • Postman should be installed in your system for testing purpose.

Initial Setup

  • Create a directory
$ mkdir imageUpload
$ cd imageUpload
  • Run npm init, it will create package.json file. This file contains information about project’s packages and dependencies.
$ npm init
  • Create entry file.
$ touch index.js
  • Install dependencies.
$ npm install express multer body-parser pg
  • Create a folder images because we need a destination for uploading images and then we will save its data to database.
$ mkdir images
  • Create a folder db and inside db create db.js file for database connection.
$ mkdir db
$ cd db
$ touch db.js
  • Create folder routes and inside route create a file image_routes.js for defining routes using Express router.
$ mkdir routes
$ cd routes
$ touch image_routes.js
  • Create another folder controllers and inside controllers create file upload.js for uploading images
$ mkdir controllers
$ cd controllers
$ touch upload.js
  • Now, we will create a PostgreSQL database with name uploader. And then, create a table with name users
CREATE TABLE users(id SERIAL NOT NULL PRIMARY KEY ,name VARCHAR(50) NOT NULL,icon VARCHAR NOT NULL)

Our final project structure will look like this:

Code

We have completed the initial steps. Let’s move to the second stage where we will write our code

  1. Setting up the Database(db.js)
const { Client } = require('pg');
const client = new Client({
user: 'postgres',
host: 'localhost',
database: 'uploader',
password: ' ',
port: 5432,
});
client.connect().then(console.log("Connected to DB"))
.catch((err)=>{console.log("Something went wrong!",err.message)});
module.exports = client;

2. Basic Express Server code(index.js)

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
const router = express.Router();
const { Client } = require('pg');
const multer = require('multer');
const port = process.env.PORT || 4000// parse requests of content-type - application/json
app.use(bodyParser.json());
/* parse requests of content-type - application/x-www-form-urlencoded /
app.use(bodyParser.urlencoded({ extended: true }));
//routes
require('./routes/image_routes')(app);
app.get('/', (req, res) => {
res.send("Heyy!!");
});
app.listen(port, () => {
console.log('Server is running on port ' + port);
})

In index.js file we have imported necessary modules and require(‘./routes/image_routes’)(app) will load the necessary routes. Also, app.listen() function helps to listen to the client requests on port no. 4000 or port defined in env file.

3. Define Routes(image_routes.js)

In routes folder, we will define routes in image_routes.js file.

const express = require('express');
const client = require('../db/db.js');
const controller = require('../controllers/upload.js');
module.exports = function(app) {

//route to upload single image
app.post('/upload/upload-single-image',
controller.upload.single('icon'),controller.uploadSingleImage);
//route to upload multiple image
app.post('/upload/upload-multiple-image', controller.upload.array('icon', 12),controller.uploadMultipleImage);


};

We have defined 2 routes of method Post type, one for uploading single image and another for uploading multiple images.

.single(fieldname): It will accept a single file with the name fieldname. The single file will be stored in req.file.

.array(fieldname, maxCount): It will accept an array of files, all with name fieldname. maxCount is max number of files that can be uploaded. The array of files will be stored in req.files.

4. Adding Multer(upload.js)

  • At first, import multer
const multer = require(‘multer’);
  • Now, we will define storage location for all the files and by what name file should be saved. And also, we can add fileFilter , it controls which files should be uploaded and which should be skipped.
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './images');
},
filename: (req, file, cb) => {

cb(null, image-${Date.now()} + path.extname(file.originalname))
//path.extname get the uploaded file extension
}
});
const multerFilter = (req, file, cb) => {

if (!file.originalname.match(/.(png|jpg)$/)) {
// upload only png and jpg format
return cb(new Error('Please upload a Image'))
}
cb(null, true)

};
exports.upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});

multer.diskStorage: The disk storage engine gives you full control on storing files to disk.

destination: It determines in which folder the uploaded files should be stored. Here, we have already created images folder for storing the files. If no destination is given, the operating system's default directory for temporary files is used.

filename: It determines the file name inside the folder. If no filename is given, each file will be given a random name without file extension.

We have applied fileFilter , before uploading it will validate if images are of png and jpg format.

  • Now, add this code.
exports.uploadSingleImage=async(req,res)=>{

const allquery =await client.query(INSERT INTO users(name, icon) VALUES ('${req.body.name}', '${req.file.filename}'));

res.status(200).json({'statusCode':200, 'status':true, message: 'Image added','data':[]});

}
exports.uploadMultipleImage=async(req,res)=>{

for(var i=0;i<req.files.length;i++){
const allquery =await client.query(INSERT INTO users(name, icon) VALUES ('${req.body.name}','${req.files[i].filename}'));
}
res.status(200).json({'statusCode':200, 'status':true,
message: 'All Image added','data':[]});
}

This query will insert name and filename in our database.

Our upload.js file will look like this.

var multer  = require('multer');
const path = require('path');
const client = require('../db/db.js');
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './images');
},
filename: (req, file, cb) => {

cb(null, image-${Date.now()} + path.extname(file.originalname))
//path.extname get the uploaded file extension
}
});
const multerFilter = (req, file, cb) => {

if (!file.originalname.match(/.(png|jpg)$/)) {
// upload only png and jpg format
return cb(new Error('Please upload a Image'))
}
cb(null, true)

};
exports.upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});
exports.uploadSingleImage=async(req,res)=>{

const allquery =await client.query(INSERT INTO users(name, icon) VALUES ('${req.body.name}', '${req.file.filename}'));

res.status(200).json({'statusCode':200, 'status':true, message: 'Image added','data':[]});

}
exports.uploadMultipleImage=async(req,res)=>{

for(var i=0;i<req.files.length;i++){
const allquery =await client.query(INSERT INTO users(name, icon) VALUES ('${req.body.name}','${req.files[i].filename}'));
}
res.status(200).json({'statusCode':200, 'status':true,
message: 'All Image added','data':[]});
}

So our code is done, let’s test our API in Postman.

Testing

In postman, create the collection.

  • Set the method Post type with correct url for uploading images. Go to body and inside body go to form-data. For images, set key to file.

1. For single image

2. For multiple image

3. In database, the data is stored.

4. In images folder which is our destination, we can see our uploaded images and with the filename that we have defined.

Our code works 😀

But let me tell you here is a catch.

Let us try to get the image through url http://localhost:4000/images/image-1633787263901.png

<img alt="" src="https://miro.medium.com/v2/resize:fit:630/1-KNJL_xxYbemi_pv-hVt_Q.png">

Cannot get image. But WHY??????

It is because our images folder cannot be accessed publicly. So to resolve this we have to serve the images folder as static files in Express. Express provides a built-in method express.static() . We will pass the name of directory that we want to serve static file as an argument in express.static() .

Add this line to index.js

app.use('/images',express.static('images'))

Now, let us check it again.

Hurrayyyyyy!! It is working now 🎉

Github link: https://github.com/Nehasunal/imageUpload

If you’ve enjoyed this learning, please click the 👏 button. And also, don’t forget to share it.

Written By Neha Sunal
reference article

Top comments (0)