Martin Carre
Martin Carre

Reputation: 1249

ExpressJS: req.body value comes as a string "[object Object]"

I'm trying to get multer working on my backend to be able to handle files. I'm sending (POST) from an Angular 9+ Front-End a FormData Object to my backend that looks like:

foo: 'test',
bar: { id: 'someId', name: 'someName' },
file: { SOMEFILE }

On my back-end I've got a server.js file:

const path = require('path');
const express = require("express");
const cors = require('cors');
const bodyParser = require("body-parser");
const mongoose = require('mongoose');

const app = express();

// SOME ROUTE IMPORTS -- Just the variable pointing to the route.


app.use(cors());

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

mongoose.connect(uri, {
    useNewUrlParser: true, 
    useUnifiedTopology: true,
    useFindAndModify: false,
    useCreateIndex: true
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB Connection Error:'));

// THERE I "USE" THE PREVIOUSLY IMPORTED ROUTES: app.use(routeX);

and the route file in question (let's call it routeX):

const express = require('express');
const router = express.Router();
const multer = require('multer');

const MIME_TYPE_MAP = {
    'image/png': 'png',
    'image/jpeg': 'jpeg',
    'image/jpg': 'jpg',
    'application/pdf': 'pdf'
}

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        const isValid = MIME_TYPE_MAP[file.mimetype];
        let error = new Error("Invalid mimeType");
        if (isValid) {
            error = null;
        }
        cb(error, "docLibrary/equipment/");
    },
    filename: (req, file, cb) => {
        const dateNow = Date.now();
        const name = dateNow + '-' + file.originalname.toLowerCase().split(' ').join('_') + '-' + file.fieldname;
        const ext = MIME_TYPE_MAP[file.mimetype];
        cb(null,name + '.' + ext)
    }
});

const upload = multer({storage: storage});
const cpUpload = upload.fields([{name: 'proforma', maxCount: 1}, {name: 'technicalDetails', maxCount: 1}]);

router.post('/newEquipment', cpUpload, async (req, res, next) => {
    const url = req.protocol + '://' + req.get('host') + '/';
    let receivedEquip = req.body;
    console.log('receivedEquip\n');
    console.log(JSON.stringify(receivedEquip));
    console.log('\n');
}

The problem is that the console.log functions gives me the following JSON for req.body:

"foo": 'test',
"bar": "[object Object]",

"bar" has become for some reason a String object that specifies the type of its value... I get the feeling that it's because of multer and the fact that I'm sending a FormData but I'm not sure where to look at here... Any ideas ?

Upvotes: 0

Views: 3701

Answers (2)

Martin Carre
Martin Carre

Reputation: 1249

Alright, so it was pretty dumb afterall... I'm not familiar with the FormData Object and by this point I wish there was a better way to send blob to the back end. Not sure it exists, so for the moment, the workaround goes like this:

ORIGIN OF THE PROBLEM:

As mentioned by our good friend VSCode - a FormData doesn't accept an object as a value. Only Blobs and strings:

Argument of type '{ test: string; secondTest: string; }' is not assignable to parameter of type 'string | Blob'.
  Object literal may only specify known properties, and 'test' does not exist in type 'Blob'.ts(2345)

SOLUTION

So all you have to do when appending to the FormData is stringify your JSON Object:

if (typeof currFormValue[key] === 'object') {
              const currObject = JSON.stringify(currFormValue[key])
              someFormDataObject.append(key, currObject);
            }

and on the server parse agains these fields to JSON like so:

Object.keys(req.body).map(reqKey => { if (reqKey === 'knowObject') { JSON.parse(req.body[reqKey]); } }

I'm sure there's a much better structure to work with out there but I know better than asking on SO which structure to use ;)

Thanks all!

Upvotes: 2

Joshua Oweipadei
Joshua Oweipadei

Reputation: 167

Ok, try doing this;

router.post('/newEquipment', cpUpload, async (req, res, next) => {
const url = req.protocol + '://' + req.get('host') + '/';
let receivedEquip = JSON.parse(JSON.stringify(req.body));
let uploadFile = req.files.file  // to get the file from the formData
console.log('receivedEquip\n');
console.log(receivedEquip);
console.log('\n');

});

Upvotes: 1

Related Questions