how can I upload file in Node JS? - node.js

I have problem while trying to upload file.
I use mongo as database and reactjs for frontend.
file appears in the database but it does not appear in the project.
I wanna appear in the directory which I set in the code.
And this is backend API.
const express = require("express");
const fileRoutes = express.Router();
let File = require("../../models/File");
const multer = require("multer");
const fs = require("fs-extra");
const storageBase = require("../../config/keys").storageBase;
const isEmpty = require("is-empty");
const addDays = require("date-fns").addDays;
const moment = require("moment-timezone");
// const fileUpload = require("express-fileupload");
// app.use(fileUpload());
var storage = multer.diskStorage({
destination: function (req, file, cb) {
const { file_type, file_owner } = req.query;
const path =
`${storageBase}` +
`${file_type}/${moment(new Date()).tz("Asia/Shanghai").format("YYYY-MM/MM-DD")}/${file_owner}`;
if (!fs.existsSync(path)) {
fs.mkdirsSync(path);
}
cb(null, path);
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
var upload = multer({
storage: storage,
limits:{
files: 5,
fieldSize: 4096 * 1024 * 1024
}
});
fileRoutes
.route("/upload")
.post(upload.single("file_data"), function (req, res) {
const {
file_type,
file_description1,
file_description2,
file_description3,
file_owner,
file_owner_job,
file_register_date,
hour,
minute
} = req.query;
let file = new File({
file_type: file_type,
file_url: req.query.file_register_date + "/" + req.files.file_data.name,
file_description1: file_description1,
file_description2: file_description2,
file_description3: file_description3,
file_owner: file_owner,
file_owner_job: file_owner_job,
file_register_date: file_register_date + " " + hour + ":" + minute
});
file
.save()
.then(file => {
res.status(200).json({ file: "file uploaded successfully" });
})
.catch(err => {
res.status(400).send("upload failed");
});
});
module.exports = fileRoutes;
But file which I select for upload does not save in my project
If u know how to do pls help me.

Related

Express Multer File Upload

I am trying to use Multer file upload in my React/Express application. But, I am getting an error that says that the file object is undefined. I have moved all of my Express server api functions into their own file, which has been working fine. I would like to keep the file upload API function in the same file as the rest of the API functions. This is what I have:
server.js
const express = require("express");
var cors = require("cors");
const config = require('config');
const { errorHandler } = require("./middleware/errorMiddleware");
const PORT = config.get('app_port') || 8000;
const app = express();
app.use(express.json());
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use("/api/meshnodes", require("./routes/myCrudRoutes"));
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
app.use(errorHandler);
myCrudRoutes.js
const express = require('express')
const router = express.Router()
const {uploadFile} = require('../controllers/myCrudContoller')
router.post('/catalog/files/upload/', uploadFile)
module.exports = router
myCrudControllers.js
const ansyncHandler = require("express-async-handler");
const multer = require("multer");
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads");
},
filename: function (req, file, cb) {
let extension = getFileExtention(file.mimetype);
cb(null, file.fieldname + "-" + Date.now() + "." + extension);
},
});
const upload = multer({ storage: storage });
const uploadFile = (upload.single("File"), (req,res, next)=>{
console.log("got file2 ")
const file = req.body;
console.log(req)
if (!file) {
const error = new Error("No File");
error.httpStatusCode = 400;
return next(error);
}
console.log("server upload ")
});
I believe the issue is with my myCrudControllers.js uploadFile function. If I have this same functionality placed directly in my server.js file, like this:
app.post(
"/catalog/files/upload",
upload.single("File"),
(req, res, next) => {
const file = req.file;
//...
It works fine, but I want to be consistent in where I have my API functions.
thanks
I refactored my code and this works:
First, I created a helper file:
uploader.js
const multer = require('multer');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, process.env.REACT_APP_UPLOAD_LOCATION);
},
filename: function (req, file, cb) {
let extension = getFileExtention(file.mimetype);
cb(null, file.fieldname + "-" + Date.now() + "." + extension);
},
});
const upload = multer({ storage: storage });
myCrudRoutes.js
const uploadHelper = require('../helpers/uploader');
router.post('/catalog/files/upload', uploadHelper.upload.single('File'), uploadFile);
myCrudControllers.js
const uploadFile = ansyncHandler(async (req,res)=>{
const file = req.file;
if (!file) {
const error = new Error("No File");
error.httpStatusCode = 400;
return error;
}
//other stuff
}, (error, req, res, next) => {
res.status(400).send({ error: error.message });
}
);

How to upload compressed image to mongodb using sharp & nodeJS

I want to upload compressed image to database. I'm using sharp ( npm package) for that purpose & using nodeJS as backend stack. I'm using multer to upload image.
My Code :
const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const cors = require('cors')
const sharp = require('sharp')
const bodyParser = require('body-parser')
const fs = require('fs')
const multer = require('multer')
const app = express()
const { HelpModel, VolunteerModel } = require('./models/model')
require('dotenv').config()
app.use(cors())
app.use(express.static('./build'))
app.use(bodyParser.urlencoded({ extended: true }));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'upload-data')
},
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname);
}
})
const fileFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')) cb(null, true)
else cb('Invalid File', false)
}
const Upload = multer({ storage, fileFilter })
const dataBase = "mongodb url"
mongoose.connect(dataBase,
{ useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("Mongoose is connected"))
.catch(e => console.log("could not connect"))
app.post('/help', Upload.single('image'), async (req, res) => {
const unique = Date.now() + '-' + '.jpeg'
const imgPath = path.resolve(__dirname + '/upload-data/' + unique);
const resize = async () => {
await sharp(req.file.path).resize(188, 280).jpeg({
quality: 100,
chromaSubsampling: ('4:4:4')
}).toFile(imgPath, (err, info) => {
if (err) console.log(err)
else console.log(info)
})
}
resize()
const newData = new HelpModel({
location: req.body.location,
contact: req.body.contact,
about: req.body.about,
img: {
data: fs.readFileSync('upload-data/' + unique),
contentType: 'image/png'
}
})
newData.save().then( () =>console.log('UPLOADED')).catch(err=>console.log(err,'ERROR OCCURED'))
const rec = await HelpModel.find({})
// res.json(rec)
res.redirect('/help')
})
const port = process.env.PORT || 8000
app.listen(port, () => console.log(`SERVER RUNNING AT PORT ${port}`))
Code is almost working as I desire, it resizes & compress the image uploaded by user and saves it in required destination in local storage.
But while uploading file to database, it is unable to access the file from local storage.
And when I'm hardcoding the file it is able to upload to database.
I'm not able to figure out why it is happening. My guess is the code might be asyncronous & data: fs.readFileSync('upload-data/' + unique) is trying to access file before it is actually upoaded & stored to local storage. After making it syncronous it is still performing in same way.

how do I receive an image that I've uploaded to my server using multer and nodejs in my angular app?

Please I'm new to Nodejs and I'm trying to create an image uploader that will upload files to my server using Nodejs and multer, but the problem is in getting the image back to be displayed in my angular app.
This is the backend code:
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const app = express();
var corsOptions = {
origin: "*",
optionsSuccessStatus: 200,
}
app.use(cors(corsOptions));
app.use(express.static('uploads'));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads");
},
filename: function (req, file, cb) {
cb(null, `${Date.now()}_${file.originalname}`);
},
})
const upload = multer({ storage });
app.post('/file', upload.single('file'), (req, res) => {
const file = req.file;
if (file) {
res.json(file);
} else {
throw new Error('File upload unsuccessful')
}
})
const port = 3000;
app.listen(port, () => console.log(`Server running on port ${3000}`));
This is my app.html code:
<input type="file" name="image" (change)="upload($event)">
This is my app.ts code:
upload(event: any) {
const file = event.target.files[0];
const formdata = new FormData();
formdata.append('file', file)
this.httpClient.post('http://localhost:3000/file', formdata)
.subscribe((data) => {
console.log(data);
},
(error) => {
console.log(error)
})
Please help me retrieve the image so that I can use it in my angular app. Thank you.
There are two ways you can achieve this. Both the approaches have their own pros and cons.
Store the image locally and send the URL back to the browser.
if (req.files) {
const fileNames = [];
for (let i = 0; i < req.files.length; i++) {
const file = req.files[i];
const relPath = "your/img/path";
const dirName = path.join(BASE_APP_PATH, relPath);
const relFileName = path.join(
relPath,
`${i + 1}_${file.originalname.replace(",", "")}`
);
const img_location = `${dirName}/${
i + 1
}_${file.originalname}`;
if (!fs.existsSync(dirName)) fs.mkdirSync(dirName, { recursive: true });
fs.writeFileSync(img_location, file.buffer, {});
fileNames.push(relFileName);
}
}
Get the image and send back base64 to the browser.
const encoded = req.files[0].buffer.toString('base64')

Upload an image and save it as base64

First in nodejs, I have succeeded to upload an image (using multer) through postman. Now I am trying to save it not as a png/jpg file, but as a base64 encrypted text file on disk. Any suggestions ?
const express=require('express');
const mongoose= require('mongoose');
const bodyparser=require('body-parser');
const cookieParser=require('cookie-parser');
const db=require('./config/config').get(process.env.NODE_ENV);
const multer = require("multer");
const path = require('path');
var fs = require('fs');
const imageStorage = multer.diskStorage({
// Destination to store image
destination: 'images',
filename: (req, file, cb) => {
cb(null, file.fieldname + '_' + Date.now()
+ path.extname(file.originalname))
// file.fieldname is name of the field (image)
// path.extname get the uploaded file extension
}
});
const imageUpload = multer({
storage: imageStorage,
limits: {
fileSize: 1000000 // 1000000 Bytes = 1 MB
},
fileFilter(req, file, cb) {
if (!file.originalname.match(/\.(png|jpg)$/)) {
// upload only png and jpg format
return cb(new Error('Please upload a Image'))
}
cb(undefined, true)
}
})
app.post('/api/uploadPicture', imageUpload.single('picture'), (req, res) => {
const contents = fs.readFileSync(req.file.path, {encoding: 'base64'});
let buff = Buffer.from(contents).toString('base64');
console.log(buff);
res.send(req.file);
}, (error, req, res, next) => {
res.status(400).send({ error: error.message })
})
Thanks ahead !
I've some ready snippets which worked well for me before. But I've commented there the part where you save a file with exact image extension. Instead I've saved the file with "txt" extension as you want (in userController).
routes/main.js
router.post('/image/base64', multerUpload.single('image'), userController.uploadBase64Image);
utils/multer.js
const multer = require('multer');
const path = require('path');
module.exports = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
const filePath = path.join(__dirname, './../uploads');
cb(null, filePath);
},
filename: function (req, file, cb) {
const extension = file.mimetype.split('/')[1];
const fileName = (new Date().getTime() / 1000 | 0) + '.' + extension;
cb(null, fileName);
}
}),
limits: {
fileSize: 1024 * 1024 * 2 // MB
},
fileFilter: (req, file, cb) => {
let valid = (file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png');
cb(null, valid);
},
});
controllers/user.js
const fs = require('fs');
const path = require('path');
const port = process.env.APP_PORT; // 3000
const appUrl = process.env.APP_URL; // http://127.0.0.1
const uploadBase64Image = async (req, res, next) => {
try {
const encoded = req.body.image;
const base64ToArray = encoded.split(";base64,");
// const prefix = base64ToArray[0];
// const extension = prefix.replace(/^data:image\//, '');
const extension = 'txt';
// if (extension === 'jpeg' || extension === 'jpg' || extension === 'png')
// {
const imageData = base64ToArray[1];
const fileName = (new Date().getTime() / 1000|0) + '.' + extension;
const imagePath = path.join(__dirname, './../uploads/') + fileName;
fs.writeFileSync(imagePath, imageData, { encoding: 'base64' });
return res.status(201).json({
error: false,
message: "Base64 Image was successfully uploaded.",
url: `${appUrl}:${port}/images/${fileName}`
});
// }
// else {
// return res.status(403).json({
// error: true,
// message: "Base64 data not valid!",
// });
// }
}
catch (e) {
return res.status(403).json({
error: true,
message: e.message,
});
}
}

TypeError: that.getDestination is not a function

I am trying to use multer for the first time to upload images from node.js to mongodb and I was running a test code as shown below, to see if everything works, i followed the documentation and i can't seem to figure out what the issue is.
the full error is this :
TypeError: that.getDestination is not a function at DiskStorage._handleFile
const router = require("express").Router();
const multer = require("multer");
const storage = multer.diskStorage({
destination: {
function(req, file, callback) {
callback(null, "./uploads/");
},
},
filename: {
function(req, file, callback) {
callback(null, new Date.now + file.originalname);
},
},
});
const upload = multer({ storage:storage });
router.post("/images", upload.single("upload"), (req, res) => {
res.send(req.file);
});
module.exports = router;
multer({ storage:storage });
switch this for
multer({ storage });
I was in the same situation as you.
from what I understand, you want to upload a file to place it in ./upload/ with as name ${Date}${Filename}.
with the code i did i got what you wanted i hope this will help you
const router = require('express').Router();
const multer = require('multer');
const path = require('path');
// this create a path like './uploads/'
const uploadsDir = path.resolve(__dirname, 'uploads');
const storage = multer.diskStorage(
{
destination: uploadsDir,
filename: (req, file, cb) => {
cb(null, `${Date.now()}${file.originalname}`);
},
},
);
const upload = multer({ storage });
router.post("/images", upload.single("upload"), (req, res) => {
res.send(req.file);
});
module.exports = router;
if you want more info i found this in a github issue : https://github.com/expressjs/multer/issues/280
const express = require('express');
const app = express()
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination : (req,file,cb)=>{
cb(null,"./Uploads/")
},
filename : (req,file,cb)=>{
const fileExt = path.extname(file.originalname);
// imp file.jpg
const fileName = file.originalname
.replace(fileExt,"")
.toLowerCase()
.split(" ")
.join("-")+"-"+Date.now();
cb(null, fileName + fileExt)
}
})
const multerObj = multer({
storage : storage, // I did (dist : storage) instead of (storage : storage) do this hope you will get your result.
limits : {fileSize : 100000000},
fileFilter : (req,file,cb)=>{
if(file.mimetype === 'image/jpg' ||
file.mimetype === "image/jpeg" ||
file.mimetype === 'immage/png' ||
file.mimetype === 'application/pdf'){
cb(null,true)
}else(
cb(new Error('Only jpg,jpeg,png file allowed.'))
)
}
});
Read the comment with code carefully and do this hope you will get your desire result.

Resources