Handling file upload in node.js multer postman

Thank you for your time :pray:

1 Like

No problem!

I think your confusion is that you’re trying to pass a JSON payload alongside your image which you can’t do.

Normally that would be done in two separate requests to two separate endpoints.

One endpoint would be for uploading the image using the Content-Type: multipart/form-data header and the other would be for sending the JSON payload with the Content-Type: application/json header.

The other option is to pass both the file and your other data in one multipart/form-data request but you’d have to change the way your Postman request is setup.

Here’s an example of what my Postman request looks like:

And my entire express app looks like this:

const express = require('express');
const multer = require('multer');

const storage = multer.diskStorage({
    destination (req, file, cb) {
        cb(null, 'storage/uploads/images');
    },
    filename (req, file, cb) {
        cb(null, file.originalname);
    }
})
const upload = multer({storage});

const app = express();
const PORT = 3000;

app.use(express.static('public'));

app.post('/upload', upload.single('image'), (req, res) => {
    if(req.file) {
        // I can access req.body from here if I want
        res.json(req.file);
    }
    else throw 'error';
});

app.listen(PORT, () => {
    console.log('Listening at ' + PORT );
});

My project’s directory structure:

Of course I uploaded all of this to GitHub as promised :slight_smile:

1 Like

I am grateful for the insights and guidance you provided.

I followed the link to GitHub but I couldn’t find the directory for this line of code. where is it located?

  • Do I have to create an index.html file because in my case I just want to upload all the products using postman and access it in my react frontend. if not what do I use in
  • You also mentioned a second option

can I pass all my data in form-data as shown here? including boolean type?

Thank you for your help so far :pray:

Here is my multer.js code

const multer = require("multer");

// checking for file type
const MIME_TYPES = {
    'imgs/jpg': 'jpg',
    'imgs/jpeg': 'jpeg',
    'imgs/png': 'png'
}

// Image Upload
const storage = multer.diskStorage({
    destination: (req, file, cb ) => {
      cb(null, ('/imgs/'));
    },
    filename: (req, file, cb) => {
        cb(null, file.originalname)
        const extension = MIME_TYPES[file.mimetype];
        cb(null, + new Date().toISOString() + '.' + extension);
    }
});

module.exports = multer({
    storage
})

repository file


const Game = require("../models/gameModel");

exports.games = async () => {
    const games = await Game.find();
    return games;
}

exports.gameById = async id => {
    const game = await Game.findById(id);
    return game;
}

exports.createGame = async payload => {
    const newGame = await Game.create(payload);
    return newGame;
}

exports.removeGame = async id => {
    const game = await Game.findById(id);
    return game;
}

controller file

const gameRepository = require("../routes/repository")



exports.createGame = async (req, res, next) => {
    
    try {
        // req.body.game = JSON.parse(req.body.game)
        const PORT = 8000;
        const hostname = req.hostname;
     const url = req.protocol + '://' + hostname + ':' + PORT + req.path;

        const payload = ({
            name: req.body.name,
            price: req.body.price,
            category: req.body.category,
            gameIsNew: req.body.gameIsNew,
            topPrice: req.body.topPrice,
            isVerOrient: req.body.IsVerOrient,
            description: req.body.description,
            image: url
        });          
        
        let eachGame = await gameRepository.createGame({
            ...payload
        });
      console.log(req.path )
        res.status(200).json({
            status: true,
            data: eachGame,
        })

    } catch (err) {
        console.log(err)
        res.status(500).json({
            error: err,
            status: false,
        })
    }
}

exports.getGames = async (req, res) => {
     
    try {
        let games = await gameRepository.games();
        res.status(200).json({
            status: true,
            data: games,
        })
    } catch (err) {
        console.log(err);
        res.status(500).json({
            error: err,
            status: false,
        })
    }
}

exports.getGameById = async (req, res) => {

    try {
       let id = req.params.id
       let gameDetails = await gameRepository.gameById(id);
        req.req.status(200).json({
          status: true,
          data: gameDetails,
        })
    } catch (err) {
        res.status(500).json({
            status: false,
            error: err
        })
    }
}


exports.removeGame = async (req, res) => {

 try {
        let id = req.params.id
        let gameDetails = await gameRepository.removeGame(id)
        res.status(200).json({
            status: true,
            data: gameDetails,
        })
     } catch (err) {
            res.status(500).json({
            status: false,
            data: err
        })
    }
}

route file

const gameRepository = require("../routes/repository")



exports.createGame = async (req, res, next) => {
    
    try {
        // req.body.game = JSON.parse(req.body.game)
        const PORT = 8000;
        const hostname = req.hostname;
     const url = req.protocol + '://' + hostname + ':' + PORT + req.path;

        const payload = ({
            name: req.body.name,
            price: req.body.price,
            category: req.body.category,
            gameIsNew: req.body.gameIsNew,
            topPrice: req.body.topPrice,
            isVerOrient: req.body.IsVerOrient,
            description: req.body.description,
            image: url
        });          
        
        let eachGame = await gameRepository.createGame({
            ...payload
        });
      console.log(req.path )
        res.status(200).json({
            status: true,
            data: eachGame,
        })

    } catch (err) {
        console.log(err)
        res.status(500).json({
            error: err,
            status: false,
        })
    }
}

exports.getGames = async (req, res) => {
     
    try {
        let games = await gameRepository.games();
        res.status(200).json({
            status: true,
            data: games,
        })
    } catch (err) {
        console.log(err);
        res.status(500).json({
            error: err,
            status: false,
        })
    }
}

exports.getGameById = async (req, res) => {

    try {
       let id = req.params.id
       let gameDetails = await gameRepository.gameById(id);
        req.req.status(200).json({
          status: true,
          data: gameDetails,
        })
    } catch (err) {
        res.status(500).json({
            status: false,
            error: err
        })
    }
}


exports.removeGame = async (req, res) => {

 try {
        let id = req.params.id
        let gameDetails = await gameRepository.removeGame(id)
        res.status(200).json({
            status: true,
            data: gameDetails,
        })
     } catch (err) {
            res.status(500).json({
            status: false,
            data: err
        })
    }
}

schema file

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// THE STRUCTURE OF THE GAME DATA

const GameSchema = new Schema({

    name: {
        type: String,
        required: [true, 'Title field is required']
    },

    price:{
        type: Number,
        required: true
    },
    category: {
        type: Number,
        required: true

    },
    gameIsNew: {
        type: Boolean,
        required: true

    },
    topPrice: {
        type: Number,
        required: true

    },
    isVerOrient: {
        type: Boolean,
       
    },
    description: {
        type: String,
        required: true
    },
    image: {
        type: String,
        required: true
    },
    date: {
        type: Date,
        default: Date.now
    }
})

const Game = mongoose.model('Game', GameSchema);

module.exports = Game;

index.js

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const gameRoutes = require("./routes/game")


const app = express();

// imgs is the folder i want the uploaded images to reside
app.use( express.static("imgs"));


app.use(bodyParser.json());



// route middleware 
app.use('/api/list', gameRoutes)

// listen for requests
app.listen(process.env.port || 8000, function(){
console.log('Now listening for request')

})

My folder structure

Started getting more errors when I keep editing so i had to undo everything and show it to you

1 Like

Should be on line 10 in src/index.js

No I only included it as an example. You can also just use Postman.

Yep! If you look at my Postman example you can just keep adding more fields and values to the body. It’s just important that the “form-body” option is selected and the Headers should be exactly as they are in the example. (I exported the Postman request and committed it to GitHub so you can check it out)

Do you have this hosted on GitHub?

It would be a lot easier for me to identify the issue if I can clone it for myself

1 Like

Thank you for your patience, I had to clone the project from bitbucket to Github.

1 Like

No problem!

Bitbucket would have worked too by the way, I’m just used to people using GitHub instead.

Either way… here you are sir! https://github.com/Godswill199/scratch9ja/pull/1

To checkout my changes and get it working on your machine run:

  1. git checkout DanJFletcher:suggestions-for-how-to-fix-file-upload
  2. from inside your backend directory mkdir storage/imgs

After that file uploads should work with Postman

1 Like

@dannyjamesfletcher I am very grateful, I am getting some crash reports in my terminal right now but I will give you feedback once I get it to work.

1 Like

@dannyjamesfletcher I got an error of TypeError: Cannot read property ‘filename’ of undefined. The error is from the controller file
image: req.file.filename. I have console.log it and it is still undefined.

Yay! it worked!
The mistake was from this line:

 cb(null, `${new Date().toISOString()}.${extension}`);

Changes:

 cb(null, `${new Date().toISOString().replace(/:/g,'-')}.${extension}`);

I added the colons in the date of my image with the hyphen in the callback function of storage.

here is my output in postman:
it worked

I also get the image file in my storage/imgs folder.

I can’t thank you enough for all the help you have offered to me @dannyjamesfletcher. I am truly grateful :pray: :slightly_smiling_face:

1 Like

Nice!!! That’s awesome :tada:

Glad you were able to get this to work!

1 Like

@godswill199 You can go through this tutorial to learn how you can upload files using NodeJS + Multer in a step by step manner: https://www.loginradius.com/blog/async/upload-files-with-node-and-multer/

1 Like

Thank you for reaching out! I have gotten it to work already :slightly_smiling_face: