skip to Main Content

I’ve built a simple user registration feature in node which stores the user’s name, email, password and an avatar image. I’m using multer to upload the image(in uploads/) and then manually place the file in a subfolder(in uploads/someUsersId/image.jpeg) and added the extension. All this is working fine but i’m storing the avatar image path as:

"C:UsersBlahDesktoptestmulter-testbackenduploads64fb0a40db0abdff97117746avatar-64fb0a40db0abdff97117746.jpeg"

For the frontend, i’m using react with redux-toolkit to store the user in state. I’m trying to read the user data and display it on a page. The text fields (name, email etc.) work fine, however, for the avatar image I get an error:

"Not allowed to load local resource: file:///C:/Users/Blah/Desktop/test/multer-test/backend/uploads/64fb0a40db0abdff97117746/avatar-64fb0a40db0abdff97117746.jpeg"

I’m pretty sure this is not the right way I should be storing the image path to begin with. Can you please recommend the correct way to go about storing image paths so that even after I upload this MERN app to a hosting provider, the image paths work.

Below is the main section of the user registeration controller where I’m handling the filing part:

if (!emailExists) {
    let user = await User.create({ name, email, password, userType });

    // uploads directory path
    const uploadsDirectoryPath = path.resolve(__dirname, '..', 'uploads');

    // make user's directory using user id
    const userDir = await mkdir(path.join(uploadsDirectoryPath, user.id), { recursive: true });

    // copy avatar file into user's directory
    await copyFile(path.join(uploadsDirectoryPath, req.file.filename), path.join(userDir, req.file.filename));

    // rename avatar file in user's directory
    const oldFileExtension = req.file.originalname.split('.')[1];
    const newFileName = `avatar-${user.id}.${oldFileExtension}`;
    await rename(path.join(userDir, req.file.filename), path.join(userDir, newFileName));

    // remove old file
    await unlink(path.join(uploadsDirectoryPath, req.file.filename));

    // user avatar file path
    const avatarPath = path.join(userDir, newFileName);

    user.avatar = avatarPath;
    await user.save();

    if (user) {
      return res.status(201).json({
        id: user._id,
        name: user.name,
        email: user.email,
        userType: user.userType,
        avatar: user.avatar,
        token: generateToken(user._id),
      });
    } else {
      res.status(500);
      throw new Error('Unable To Register User!');
    }
  } else {
    res.status(400);
    throw new Error('Email address is already in use. Please choose another!');
  }

2

Answers


  1. Chosen as BEST ANSWER

    I was making a really stupid mistake. To check whether I could directly access the image in the browser I was using "http://localhost:5000/uploads/64fb0a40db0abdff97117746/avatar-64fb0a40db0abdff97117746.jpeg" with obviously would not work because in my main.js file, where im creating my express server I used "app.use(express.static('./uploads'))". So, in the above image link I had added the extra "uploads" part. Now I can access the image directly in the browser and also in my frontend. However, there seems to be a slight drawback to the approach I am using.

    const serverURL = `${req.protocol}://${req.get('host')}`; //http://localhost:5000
    const avatarPath = `${serverURL}/${user.id}/${newFileName}`; //http://localhost:5000/64fb0a40db0abdff97117746/avatar-64fb0a40db0abdff97117746.jpeg
    

    To create the avatarPath, I tried using path.join(serverURL, user.id, newFilename) but it just returns one slash instead of two, meaning http:localhost. I read online that this is the way path.join() is suppose to work and this is not a bug. Since i'm using Windows then would this not be an issue for a person using MacOS because the path structure is different. One solution which came to mind was to check the user's operating system first and then accordingly form the path. But I feel there is a more elegant method to this problem...Kindly, share if there is a better approach.


  2. you just need to save image in folder and in root app/server.js file set path like this

    const uploadsDirectoryPath = path.resolve(__dirname, 'uploads');
    

    and don’t forget to add your node server domain name with your file location.

    Example
    Your client is on http://localhost:3000
    Your image is on http://localhost:8000

    send your image from node server like this :- http://localhost:8000/image/car.png

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search