2

As the title suggests, I am getting error: {"message": "ENOENT: no such file or directory, open 'E:\\astrology\\utils\\uploads\\1600798534862qf.png'"} in my project even after passing every required configs.

Note: I've divided 'app' into two parts: main 'app.js' and 'appRoute.js' for more dynamic and code clarity.

app.js

const express = require("express");
const path = require("path");

const app = express();
const directory = path.join(__dirname, "utils/uploads");
app.use("/uploads", express.static(directory));

require("./config/database/db")();
require("./config/approutes/appRoutes")(app);

module.exports = app;

appRoute.js

require("dotenv").config();

const morgan = require("morgan");
const bodyParser = require("body-parser");
const cors = require("cors");

const productRoutes = require("../../api/routes/products");

module.exports = function (app) {
  app.use(morgan("dev"));

  app.use(bodyParser.urlencoded({ extended: true, limit: "100mb" }));
  app.use(bodyParser.json());

  app.use(cors({ credentials: true, origin: true }));

  app.use("/products", productRoutes);
  
  app.use((req, res, next) => {
    const error = new Error("Not found");
    error.status = 404;
    next(error);
  });

  app.use((error, req, res, next) => {
    console.log('SHOW ERROR', error);
    
    res.status(error.status || 500);
    res.json({
      error: {
        message: error.message,
      },
    });
  });
};

fileUpload.js

const multer = require("multer");

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, __dirname + "/uploads");
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + file.originalname.replace(/\s+/g, "-"));
  },
});

const fileFilter = (req, file, cb) => {
  // reject a file
  if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
    cb(null, true);
  } else {
    cb(null, false);
  }
};

const upload = multer({
  storage,
  limits: {
    fileSize: 1024 * 1024 * 5,
  },
  fileFilter: fileFilter,
});

module.exports = upload;

Product.js (controller)

exports.create_product = async (req, res, next) => {
  const { title, min_content, content } = req.body;

  console.log("req files", req.files);

  try {
    const product = new Product({
      title,
      min_content,
      content,
    });

    const new_product = await product.save();
    console.log("error caught", new_product);

    if (new_product) {
      res.status(201).json({ msg: "New product added", new_product });
    } else {
      res.status(400).json({ msg: "Unable to create new product" });
    }
  } catch (error) {
    res.status(500).json({ msg: "Internal server error", error });
  }
};

Product.js (route)

const express = require("express");
const router = express.Router();

const ProductController = require("../controllers/products");
const uploadMW = require("../middleware/fileUpload");

router.get("/all", ProductController.get_products);
router.post("/new", uploadMW.fields([{ name: "thumbnail" }, { name: "image" }]), ProductController.create_product
);

module.exports = router;

Directory structure

directory structure

My OS is windows, so I have included the config to replace the (:) from file names, but nothing seems to work for me. Any help to resolve the same is appreciated.

program_bumble_bee
  • 439
  • 2
  • 25
  • 57

3 Answers3

6

app.js file will be like this

// modules =================================================
var express = require('express');
var app = express();
const logger = require('morgan');
var bodyParser = require('body-parser');
const indexRouter = require("./routes/index");
const cors = require('cors');
const path = require("path");
config = require("./environments/index");
var http = require('http').Server(app);

// configuration ===========================================
var port = config.PORT || 8081; // set our port

app.use(bodyParser.json({ limit: '50mb' }));

app.use(bodyParser.urlencoded({
limit: '50mb',
extended: true,
parameterLimit: 50000
}));
app.use(cors());
app.use(logger('dev'))
app.use("/api", indexRouter);

app.use(express.static(path.join(__dirname, "/build")));

http.listen(port, () => {
   console.log('Magic happens on port ' + port); // shoutout to the user
});

exports = module.exports = app;

create multerhelper.js file in your app nd add below code in it

const multer = require('multer');

// const fs = require('fs');
let fs = require('fs-extra');

let storage = multer.diskStorage({
destination: function (req, file, cb) {
   let path = `/uploads`;
   fs.mkdirsSync(path);
   cb(null,  __dirname + path);
},
filename: function (req, file, cb) {
   // console.log(file);

 cb(null, Date.now() + file.originalname.replace(/\s+/g, "-"));
}
})

 var upload = multer({ storage: storage });

 let createUserImage = upload.single('images');


 let multerHelper = {
 createUserImage,

 }

 module.exports = multerHelper;

In your product.js(route) file import this file

  const multerhelper = require("../multerhelper.js");  
  router.post("/new",multerhelper.createUserImage,ProductController.
  create_product);
Aryan
  • 3,338
  • 4
  • 18
  • 43
1

Your directory structures look messed up. Your uploads directory in fileUpload.js is referring to a directory in ./api/middleware/uploads when it should be referencing ./utils/uploads (the paths relative to the module are incorrect).

// fileUpload.js
const multer = require("multer");
const path = require("path");

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.resolve(__dirname, `..${path.sep}..${path.sep}`, `${path.sep}utils${path.sep}uploads`);
  },

__dirname returns the directory that the current file is in. So in this case it will be middleware. (I am deducing this based on the require in your Product.js file).

Try fixing the path to the uploads directory in the fileUpload.js by pointing at the same directory that the static files are being served from.

Also, I seen in the chat that Arya started with you that you are now managing to get it working on a *nix OS but not on windows.

Try changing your path separators to use path.sep from the path module. Arya's solution above looks good, i.e. the file paths now all look fixed relative to the static uploads directory. I have updated my answer to use path.sep based on the original code that you published and the directory structure that you provided.

jeeves
  • 1,871
  • 9
  • 25
  • 1
    Sorry for looking up late. I have updated my question – program_bumble_bee Oct 03 '20 at 11:06
  • @bubble-cord I updated my answer based on updated directory structure and the fact that it works on *nix but not Windows – jeeves Oct 04 '20 at 19:17
  • Thanks, your solution did help to resolve the 'EONENT' not found issue, & img is getting upload as seen from postman while testing. But, the img is not yet getting saved to the db. The file object on console has double \\, which I think causing the problem. `req file { fieldname: 'thumbnail', originalname: 'wp1910893.jpg', encoding: '7bit', mimetype: 'image/jpeg', destination: 'E:\\utils\\uploads', filename: '1601924503515wp1910893.jpg', path: 'E:\\utils\\uploads\\1601924503515wp1910893.jpg', size: 364652 }`. I am unable to figure out this double \\ behaviour – program_bumble_bee Oct 05 '20 at 19:04
  • No - that is to be expected with Windows paths. Here is a good article on best practices for traversing the filesystem with nodejs https://shapeshed.com/writing-cross-platform-node/ – jeeves Oct 06 '20 at 12:00
  • If the EONENT issue is resolved accept the answer that you believe helped it. Not getting saved to the DB is probably another issue – jeeves Oct 06 '20 at 12:02
1

Finally I was able to resolve this. I am posting the solution if anyone comes across the same issue (Windows OS to be specific), this will surely help.

I changed my directory structure by shifting the uploads folder directly outside instead of /utils/uploads(for the sake of easeness) & made a minor change in fileUpload.js:

const multer = require("multer");

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, process.cwd() + "/uploads/");
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + file.originalname.replace(/\s+/g, "-"));
  },
});

const fileFilter = (req, file, cb) => {
  // reject a file
  if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
    cb(null, true);
  } else {
    cb(null, false);
  }
};

const upload = multer({
  storage,
  limits: {
    fileSize: 1024 * 1024 * 5,
  },
  fileFilter: fileFilter,
});

module.exports = upload;

Instead of using __dirname, I replaced it with process.cwd(), and appended my target folder :

destination: function (req, file, cb) {
    cb(null, process.cwd() + "/uploads/");
  },

Reference: What's the difference between process.cwd() vs __dirname?

P.S. Thanks to @jeeves & @Arya for their thorough suggestions :)

program_bumble_bee
  • 439
  • 2
  • 25
  • 57