Ronny Efronny
Ronny Efronny

Reputation: 1498

Parse images inside a JSON in HTTP request

I in my React app I send a request containing a JSON body with various fields, among which is an array of File type images.

const body = {
  title: 'title',
  price: 100,
  images: [...]
};

axios.post(url, body);

This doesn't work and the images array arrives at the Express app empty. I have consulted the internet and have tried using FormData. However, all the solutions I saw (example) only have images in them, i.e.

const images = [...];
const data = new FormData();
images.forEach(img => data.append(img.title, img));

But I want the entire thing - the text and the images, because this input is supposed to go into MongoDB. I have tried simply putting the entire object in a FormData:

const data = new FormData();
data.append('body', body);

But I must not understand how FormData actually works because trying to iterate over the req.body over in Express just yields nothing:

app.get((req, res) => {
  const data = Object.fromEntries(req.body) // yields nothing
}

Any other attempts like using multer reinforce that I'm doing something wrong, because I cannot for the life of me get a non-empty request body.

What I want to do is to be able to send a full HTTP body of data that includes text, numbers, and an array of images, such that over on the Express app I could save those images to disk. Any nice suggestions would be appreciated.

Upvotes: 0

Views: 1383

Answers (1)

Denes
Denes

Reputation: 106

You cannot use json to send images(not the original file), but there's an option with form data. First, you have to separate the files from the normal data, and parse the normal data to a string.

const images = [...];
const body = new FormData();
// you have to put the images in the same field, and the server will receive an array
images.forEach(img => body.append('images', img));
// the other data to send
const data = {
  someData: true,
  moreData: 1,
arrOfNormalData: [23,10];
}
const parsedData = JSON.stringify(data);
body.append('_jsonData', parsedData);
axios.post(url, body);

You are sending the json data as string in the _jsonData field of your request. Then en your node server, you have to install multer on configure it ej

const path = require('path');
//this is for a random id for file name
const { nanoid } = require('nanoid');
const multer = require('multer');

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads')
  },
  filename: function (req, file, cb) {
    cb(null, nanoid() + path.extname(file.originalname));
  }
})
 
const upload = multer({ storage: storage });

Then you have can create a middleware to parse the data (remember we converted it to a string) to a object.

const parseJson = (field = '_jsonData') => {
    return (req, res, next) => {
        if (req.body[field] && typeof req.body[field] === 'string') {
            req.body = JSON.parse(req.body[field]);
        }
        next();
    };
};

Then lets use in in our route

app.get(upload.array('images',10),parseJson(),(req, res) => {
  const data = req.body;// here the json data
const files = req.files;// here the uploaded files
}

We have added the upload.array('images',10) where images is the field of files and 10 is the max number of files We added our parseJons middleware to parse the string to json Don't use base64, you can have issues if you are working with base64. Use formdata

Upvotes: 1

Related Questions