req.file.stream is undefined

Viewed 1395

I'm having troubles with node 16 and ES6. I'm trying to make a upload file controller but i'm stuck with req.file.stream which is undefined I'm using multer to handle upload files.

The first issue was __dirname undefined that I was able to fix with path and New Url.

The error I got with pipeline

node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

TypeError [ERR_INVALID_ARG_TYPE]: The "source" argument must be of type function or an instance of Stream, Iterable, or AsyncIterable. Received undefined

my userRoutes.js

import express from "express";
import { signin, signup, logout } from "../Controller/AuthController.js";
import {
  getUsers,
  getUser,
  updateUser,
  deleteUser,
  follow,
  unfollow,
} from "../Controller/UserController.js";
import { upload } from "../Controller/UploadController.js";
import multer from "multer";

const router = express.Router();
// Auth
router.post("/signin", signin);
router.post("/signup", signup);
router.post("/logout", logout);

// users
router.get("/", getUsers);
router.get("/:id", getUser);
router.patch("/:id", updateUser);
router.delete("/:id", deleteUser);
router.patch("/follow/:id", follow);
router.patch("/unfollow/:id", unfollow);

// upload
router.post("/upload", multer().single("file"), upload);
export default router;

And my UploadController.js


import fs from "fs";
import { promisify } from "util";
import stream from "stream";

const pipeline = promisify(stream.pipeline);
// const { uploadErrors } = require("../utils/errors.utils");
import path from "path";
const __dirname = path.dirname(new URL(import.meta.url).pathname);

export const upload = async (req, res) => {
  try {
    // console.log(req.file);
    console.log(__dirname);
    if (
      !req.file.mimetype == "image/jpg" ||
      !req.file.mimetype == "image/png" ||
      !req.file.mimetype == "image/jpeg"
    )
      throw Error("invalid file");

    if (req.file.size > 2818128) throw Error("max size");
  } catch (err) {
    const errors = uploadErrors(err);
    return res.status(201).json({ err });
  }
  const fileName = req.body.name + ".jpg";
  await pipeline(
    req.file.stream,
    fs.createWriteStream(
      `${__dirname}/../client/public/uploads/profil/${fileName}`
    )
  );

  try {
    await User.findByIdAndUpdate(
      req.body.userId,
      { $set: { picture: "./uploads/profil/" + fileName } },
      { new: true, upsert: true, setDefaultsOnInsert: true },
      (err, docs) => {
        if (!err) return res.send(docs);
        else return res.status(500).send({ message: err });
      }
    );
  } catch (err) {
    return res.status(500).send({ message: err });
  }
};
2 Answers

Multer gives you the file as a Buffer, not a Stream. req.file.stream is not valid property, but req.file.buffer is: https://github.com/expressjs/multer#file-information.

From the look of your code, you're trying to save the file on disk. You can use multer's DiskStorage for that. Create a storage instance and pass it to the multer instance as a configuration:

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, `${__dirname}/../client/public/uploads/profil/`);
  },
  filename: function (req, file, cb) {
    cb(null, req.body.name + '.jpg');
  },
});

const upload = multer({ storage });

router.post('/upload', upload.single('file'), upload);

Have a look at this free Request Parsing in Node.js Guide for working with file uploads in Node.js.

if you want to use req.file.stream, you will need to install this version of multer:

npm install --save multer@^2.0.0-rc.1

and your code will work perfectly, just change your req.file.mimetype to req.file.detectedMimeType !!

Related