Search code examples
javascriptnode.jsreactjsmongodbcloudinary

My request works in Postman ut not in browser (React, Node, Cloudinary)


I have a page where i made the backend in NodeJs + MongoDb and the frontend with React. In the backend i have a middleware that i use to upload images to Cloudinary. For example one route is for create a new pet and when i do the post request with Postman everything goes good, the new pet is created well in the db and also have the url of Cloudinary in the image place. The problem come when i try to do the same with a form in react... Everything goes "good" too, but in the image place (where with postman i have the clodinary url), now is empty...

The node controller code:

const petCreatePost = async(req, res, next) => {
    const { type, name, avatar, age, sex, breed, size, isVaccinated, isSterilized, isDewormed, microchip, province, shelter, status } = req.body;

    try {

        const newPet = new Pet({
            type,
            name,
            avatar: req.imageUrl ? req.imageUrl : '',
            age,
            sex,
            breed,
            size,
            isVaccinated,
            isSterilized,
            isDewormed,
            microchip,
            province,
            shelter,
            status
        });

        const createdPet = await newPet.save();

        return res.status(200).json('Mascota creada correctamente', { pet: createdPet });
    } catch (error) {
        return next(error);
    }

}

Cloudinary middleware:

const multer = require('multer');
const path = require('path');
const fs = require('fs');
const cloudinary = require('cloudinary').v2

const ACCEPTED_FILE = [ 'image/jpg', 'image/jpeg', 'image/png' ];

const fileFilter = (req, file, cb) => {
    if(!ACCEPTED_FILE.includes(file.mimetype)) {
        const error = new Error ('Extensión del archivo inválida.')
        error.status = 400;
        return cb(error);
    }
    return cb(null, true);
};

const storage = multer.diskStorage({
    filename: (req, file, cb) => {
        const fileName = `${Date.now()}-${file.originalname}`;
        cb(null, fileName);
    },
    destination: (req, file, cb) => {
        const directory = path.join(__dirname, '../public/uploads');
        cb(null, directory);
    }
});

const upload = multer({
    storage,
    fileFilter,
});

const uploadToCloudinary = async (req, res, next) => {
    try {
        console.log('req', req);
        if(req.file) {
            const path = req.file.path;
            const image = await cloudinary.uploader.upload(path);
    
            req.imageUrl = image.secure_url;
            console.log('image url', req.imageUrl);
    
            return next();
        } else {
            return next();
        }
    } catch (error) {
        return next(error);
    }
};

module.exports = { upload, uploadToCloudinary };

How i use the middleware:

router.post('/new', [upload.single('avatar'), uploadToCloudinary], controller.petCreatePost);

The react component:

import React, { useContext } from 'react';

export const NewPet = () => {

  const submitForm = async (e) => {
    e.preventDefault();

    const { type, name, age, avatar, sex, breed, size, isVaccinated, isSterilized, isDewormed, microchip, province, status } = e.target;

    const form = {
      type: type.value,
      name: name.value,
      age: age.value,
      sex: sex.value,
      breed: breed.value,
      size: size.value,
      isVaccinated: isVaccinated.value,
      isSterilized: isSterilized.value,
      isDewormed: isDewormed.value,
      microchip: microchip.value,
      province: province.value,
      status: status.value
    };

    // const form = new FormData();
    // form.append('type', type.value);
    // form.append('name', name.value);
    // form.append('age', age.value);
    // form.append('sex', sex.value);
    // form.append('breed', breed.value);
    // form.append('size', size.value);
    // form.append('isVaccinated', isVaccinated.value);
    // form.append('isSterilized', isSterilized.value);
    // form.append('isDewormed', isDewormed.value);
    // form.append('microchip', microchip.value);
    // form.append('province', province.value);
    // form.append('status', status.value);
    // form.append('avatar', imagenPrueba);

    try {
      const pet = await newPet(form);
      console.log('pet', pet);

    } catch (err) {
      console.log(err);
    }
  }

The part of the code where is commented is an alternative that i try to use, because i'm sending a file and i have to use a FormData, but is not working too. I also checked that the form have the enctype="multipart/form-data".

And by last the "newPet" function that i use to connect to the back:

export const newPet = async(form) => {
    const req = await fetch(newPetUrl, {
        method: "POST",
        headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*",
        },
        credentials: "include",
        body: JSON.stringify(form),
    });

    const response = await req.json(form);

    if (!req.ok) {
        throw new Error(response.message);
    }

    return response;
};

I hope someone can help me.. Thanks!


Solution

  • You need to await the url from cloudinary. I had this problem too