Image upload isn't working using multer - javascript

I setup multer like this
let multer = require('multer');
let apiRoutes = express.Router();
let UPLOAD_PATH = '../uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, UPLOAD_PATH);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now());
}
});
let upload = multer({ storage: storage });
and in route I am getting data and an image and use multer like!
apiRoutes.post('/update', passport.authenticate('jwt', { session: false }), (request, response) => {
let record = {
name: request.body.name,
location: request.body.location,
about: request.body.about,
userid: request.body.userid,
avatar: request.body.filename
};
let userData = {
name: request.body.name
};
if (request.body.filename) {
upload(request, response, (error) => {
});
}
profile.findOneAndUpdate({ userid: request.body.userid }, record, {new: true}, (error, doc) => {
if (error) response.json(error);
user.findOneAndUpdate({ _id: request.body.userid }, record, (error, result) => {
if (error) throw error;
response.json(doc);
});
});
});
What is happening with this code is that when I do not send an image to backend then I get data from front end and store it into database. But when I send image along side data then it return POST /api/1.0/profile/update 401 0.396 ms - -.
It means I am not getting any data at all. Whats wring with the code here?

You can't use Multer in your /update route. Use Multer in your router like this:
var upload = multer({ dest: 'uploads/' })
apiRoutes.post('/profile', upload.single('image'), function (req, res, next) {
// Uploaaded
})
if you add it and still can't get our file, you should update your form with this parameter: enctype="multipart/form-data"

Related

Multer next() funtion not a funtion

I'm developing this server based on this tutorial, https://www.bezkoder.com/angular-12-node-js-express-mysql/ now I'm in need of add some file upload functionalities, using Multer. but each time I try to us it, I get this error:
/home/miguel/Documents/angular_projs/examples/server/node_modules/multer/lib/make-middleware.js:45
next(err)
^
TypeError: next is not a function
at done (/home/miguel/Documents/angular_projs/examples/server/node_modules/multer/lib/make-middleware.js:45:7)
when i use it here:
//File upload configuration
const maxSize = 2 * 1024 * 1024;
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "/resources/static/assets/uploads/");
},
filename: (req, file, cb) => {
console.log(file.originalname);
cb(null, file.originalname);
},
});
let uploadFile = multer({
storage: storage,
limits: { fileSize: maxSize },
}).single("file");
/* ---------------------------------------------------------------------------------------------------- */
//Upload Files
exports.file_upload = async (req, res) => {
let number = req.params.number;
try {
await uploadFile(req, res);
if (req.file == undefined) {
return res.status(400).send({ message: "Please upload a file!" });
}
res.status(200).send({
message: "Uploaded the file successfully: " + req.file.originalname,
});
} catch (err) {
if (err.code == "LIMIT_FILE_SIZE") {
return res.status(500).send({
message: "File size cannot be larger than 2MB!",
});
}
res.status(500).send({
message: `Could not upload the file: ${req.file.originalname}. ${err}`,
});
}
//Check if empty
//res.status(200).json({msg:`${s03}`});
};
I've checked other tutorial and it's suppose to work
Try passing in next as a parameter.
...
exports.file_upload = async (req, res, next) => {
let number = req.params.number;
try {
await uploadFile(req, res, next);
...

Image file upload with node.js

I'm trying to adapt my code to upload files, but I'm not getting it, I looked in the community and I didn't understand, I'm still new to this. It always falls on the error json return, do you know what it can be?
File where you have the logic
async img(request, response){
multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./Uploads")
},
filename: (req, file, cb) => {
cb(null, Date.now().toString() + '-' + file.originalname)
},
fileFilter: (req, file, cb) => {
const extensionImg = ['image/png', 'image/jpg', 'image/jpeg'].find
(formatPermitted => formatPermitted == file.mimetype)
if(extensionImg){
return cb(null, true)
}
return cb(null, false)
}
})
}).single('image')
if(request.file){
return response.status(200).json({erro: false, message: "ok"});
}else{
return response.status(400).json({erro: true, message: "error"});
}
}
File where the route is
const IncidentsController = require('./controllers/IncidentsController');
const routes = express.Router();
routes.post('/uploads', IncidentsController.img)
multer(...).single(...) returns a middleware function. That middleware function that it returns has to be actually called in order to do something.
Typically, you would define the middleware outside a request handler and then use it as middleware on one or more request handlers.
const imgMulterMiddleware = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./Uploads")
},
filename: (req, file, cb) => {
cb(null, Date.now().toString() + '-' + file.originalname)
},
fileFilter: (req, file, cb) => {
const extensionImg = ['image/png', 'image/jpg', 'image/jpeg'].find
(formatPermitted => formatPermitted == file.mimetype)
if(extensionImg){
return cb(null, true)
}
return cb(null, false)
}
})
}).single('image');
Then, use that middleware as needed:
routes.post('/uploads', imgMulterMiddleware, (req, res) => {
// do something with req.file here which will be set
// by the middleware if it was successful
if (req.file) {
res.json({erro: false, message: "ok"});
} else {
res.status(400).json({erro: true, message: "error"});
}
});

uploading two files from two fields with multer as middleware

i'm trying to upload two files with different file extensions with multer from two fields but when i try it with postman the result always for the file is null, what is the solution for my problem? here is my code
middleware/uploadEpub
const multer = require('multer')
exports.uploadEpub = (epubFile, coverFile) => {
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads")
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname.replace(/\s/g, ""))
}
})
const upload = multer({
storage
}).fields([{name: "bookFile", maxCount: 1},{name: "coverFile", maxCount: 1}])
}
controller/book
exports.addBook = async (req, res) => {
try {
const { ...data } = req.body
const newBook = await book.create({
...data,
bookFile: req.file,
coverFile: req.file
})
let bookData = await book.findOne({
where: {
id: newBook.id
},
attributes:{
exclude: ['createdAt','updatedAt']
}
})
bookData = JSON.parse(JSON.stringify(bookData))
res.send({
status: "Success",
Book: {
...bookData
}
})
} catch (error) {
console.log(error)
res.status(500).send({
status: "Failed",
message: "Server Error"
})
}
}
Multer set up
const multer = require('multer')
const path = require('path')
const { nanoid } = require('nanoid')
//Set Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: (req, file, callback) => {
const id = nanoid(6)
const newFilename = `${file.fieldname}_${id}-${new Date().toISOString().replace(/:/g, '-')}${path.extname(file.originalname)}`
callback(null, newFilename)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: 5572864 }, // up to 5.5 MB
fileFilter: (req, file, callback) => {
checkFileType(file, callback)
},
})
//Check File Type
const checkFileType = (file, cb) => {
//Allowed extensions
const fileType = /jpeg|jpg|png|gif|svg|pdf|epub/
//Check extension
const extname = fileType.test(path.extname(file.originalname).toLowerCase())
//Check mimetype
const mimetype = fileType.test(file.mimetype)
if (extname && mimetype) {
return cb(null, true)
} else {
return cb('Error: wrong file type!')
}
}
module.exports = upload
/***** middlewares.js *****/
module.exports.imageUploader = (req, res, next)=>{
const files = req.files
const uploadedFiles = []
for (var i = 0; i <images.length; i++){
uploadFiles.push('https://yourserver.com/public/uploads/' + files[i].filename)
}
req.uploadFiles = uploadFiles.toString() //appending files to req
next()
return
}
/**** index.js or app.js ****/ //where your routes are defined
router.post('/books/add', upload.array('images', 10), imageUploader, book.addBook) // allowing up to 10 files to be uploaded, calling imageUploader as a middleware
/*** Controllers/book ***/
exports.addBook = async (req, res) => {
const uploadedFiles = req.uploadFiles; //catching files from imageUploader middleware
// ... rest of your code
}
Try to upload the file as form-data in postman, and put the key with the same name that you have set in multer, the postman will look like this:
Try this:
const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
})

Simple Node.JS REST API call

I have a simple app that requires a REST API call to perform CRUD (Create,Read,Update,Delete). However, i can't seem to get the REST API working.
When it's executing the put operation, i'm getting
"api.js:81 Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at callAPI (api.js:81)"
I'm using Api.js to check the API calls.
api-photos.js
//photos.js
var express = require('express');
var router = express.Router();
var multer = require('multer');
var photoController = require('../../controllers/photoController');
var upload = multer({
storage: photoController.storage,
fileFilter: photoController.imageFilter
});
//import PhotoService
const PhotoService = photoController.PhotoService;
router.use((req, res, next)=>{
//set mime type for all request and origin
res.set({
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,OPTIONS',
"Access-Control-Allow-Headers":"Content-Type, Access-Control-Allow-Headers",
'Content-type':'applicaion/json'
});
if(req.method == 'OPTIONS'){
return res.status(200).end();
}
next();
})
// photos - list
router.get('/', (req, res, next)=>{
PhotoService.list()
//returns promise - argument passed photos
.then((photos)=>{
console.log(`API: Found images: ${photos}`);
res.status(200);
//set content type header to application/json - set correct mime type
res.send(JSON.stringify(photos));
});
})
// photos/:photoid - find
router.get('/:photoid', (req, res, next)=>{
PhotoService.read(req.params.photoid)
//returns promise - argument passed photos
.then((photo)=>{
console.log(`API: Found images: ${photo}`);
res.status(200);
//set content type header to application/json - set correct mime type
res.send(JSON.stringify(photo));
}).catch((err)=>{
});
});
// /photos POST create
router.post('/', upload.single('image'), async (req, res, next)=>{
var path = "/static/img/" + req.file.filename;
var photo = {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
imageurl: path,
title: req.body.title,
filename: req.file.filename,
description: req.body.description,
size: req.file.size / 1024 | 0
}
//calling on photo service to return json object
try{
const photoSave = await PhotoService.create(photo);
res.status(201);
res.send(JSON.stringify(photoSave));
}catch(err){
console.log(err);
throw new Error("PhotoSaveError", photo);
}
});
// /photos/photoid: PUT - update
router.put('/:photoid', (req, res, next)=>{
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
PhotoService.update(req.params.photoid, putdata)
console.log()
.then((updatePhoto)=>{
res.status(200);
res.send(JSON.stringify(updatedPhoto));
}).catch((err)=> {
res.status(404);
res.end();
});
});
// /photos/photoid: DELETE - delete
router.delete('/:photoid', (req, res, next)=>{
PhotoService.delete(req.params.photoid)
.then((photo) => {
console.log(`Found images: $(photo)`);
res.status(200);
res.send(JSON.stringify(photo));
}).catch((err)=> {
res.status(404);
res.end();
});;
});
module.exports = router;
photo.js
//photos.js
var express = require('express');
var router = express.Router();
var app = express();
var multer = require('multer');
var photoController = require('../controllers/photoController');
var flash = require('express-flash');
//create upload object- intialize
var upload = multer({
storage: photoController.storage,
fileFilter: photoController.imageFilter
});
//Photo model import is required
var Photo = require('../models/photoModel');
const PhotoService = photoController.PhotoService
//flash messaging
router.use(flash());
//LIST - Get request to search database for our photos
router.get('/', (req, res, next)=>{
//search the DB for the photos
PhotoService.list()
.then((photos)=>{
//call photos view
res.render('photos', {
photos : photos,
flashMsg: req.flash("fileUploadError")
});
})
.catch((err)=>{
if (err) {
res.end("ERROR!");
}
});
});
//FIND - route for getting photo Details with form for editing
router.get('/:photoid', (req, res, next)=>{
console.log("finding "+req.params.photoid);
PhotoService.read({'_id': req.params.photoid})
//return promoise then handle it to render photo
.then((photo)=>{
res.render('updatePhoto', {
photo: photo,
flashMsg: req.flash("photoFindError")
});
}).catch((err)=>{
if (err) console.log(err);
});
});
//DELETE - route for deleting the photos
router.delete('/delete/:photoid', function(req, res){
PhotoService.delete({'_id': req.params.photoid})
.then((photos) => {
res.redirect('/photos');
});
});
//UPDATE - route for posting newly updated details
router.post('/:photoid', (req, res, next)=>{
PhotoService.update({'_id': req.params.photoid})
//return promoise then set photo data details
.then((photo)=>{
var data = {
title: req.body.title,
description: req.body.description
}
//set the data, save the photo details and redirect to photo list
photo.set(data);
photo.save().then(()=>{
res.redirect('/photos');
});
})
.catch((err)=>{
if (err) console.log(err);
});
});
//CREATE - post fields to the server and save them
router.post('/', upload.single('image'), (req, res, next)=>{
var path = "/static/img/" + req.file.filename;
var photo = {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
imageurl: path,
title: req.body.title,
filename: req.file.filename,
description: req.body.description,
size: req.file.size / 1024 | 0
}
//Saving photo to DB
var photo = new Photo(photo);
photo.save()
.then(()=>{
//redirect after save, if succesfull
res.redirect('/photos');
})
//Catch error logs error
.catch((err)=>{
if (err){
console.log(err);
throw new Error("PhotoSaveError", photo);
}
});
});
//function will get called if above gets unhandled error - flash to display image and redirect
router.use(function(err, req, res, next){
console.error(err.stack);
if (err.message == "OnlyImageFilesAllowed"){
req.flash('fileUploadError', "Please select an image file with jpg, png, or gif")
res.redirect('/photos');
//2nd condition error if there was a problem saving
} else if (err.message == "PhotoSaveError"){
req.flash('photoSaveError', "There was a problem saving the photo")
res.redirect('/photos');
} else{
next(err);
}
});
//export the module
module.exports = router;
api.js
// wrap in IIFE to control scope
(function(){
const baseURL = 'http://localhost:8080';
function testAPIs(){
// test list first
var testId = '';
var testJSON = {};
// list
callAPI('GET', '/api/photos', null, null)
.then((list)=>{
console.log('\n\n***************************\nlist results:');
console.log(list);
testId = list[0]._id;
// create
let input = document.querySelector('input[type="file"]')
let data = new FormData()
data.append('image', input.files[0]);
data.append('title', 'My API Test Title');
data.append('description','This is an AJAX API test');
callAPI('POST', '/api/photos', null, data)
.then((photo)=>{
photoId = photo._id;
savedPhoto = photo; // keep a handle to the created photo object
console.log('\n\n***************************\ncreate results:');
console.log(photo);
// find
callAPI('GET','/api/photos/'+photoId, null, null)
.then((photo)=>{
console.log('\n\n***************************\nfind results:');
console.log(photo);
// update
testJSON.description += ' appended by the AJAX API ';
callAPI('PUT','/api/photos/'+photoId, null, savedPhoto)
.then((photo)=>{
console.log('\n\n***************************\nupdate results:');
console.log(photo);
//delete
callAPI('DELETE', '/api/photos/'+photoId, null, null)
.then((result)=>{
console.log('\n\n***************************\ndelete result:');
console.log(result);
})
});
});
});
})
.catch((err)=>{
console.error(err);
});
}
async function callAPI(method, uri, params, body){
jsonMimeType = {
'Content-type':'application/json'
}
try{
/* Set up our fetch.
* 'body' to be included only when method is POST
* If 'PUT', we need to be sure the mimetype is set to json
* (so bodyparser.json() will deal with it) and the body
* will need to be stringified.
* '...' syntax is the ES6 spread operator.
* It assigns new properties to an object, and in this case
* lets us use a conditional to create, or not create, a property
* on the object. (an empty 'body' property will cause an error
* on a GET request!)
*/
var response = await fetch(baseURL + uri, {
method: method, // GET, POST, PUT, DELETE, etc.
...(method=='POST' ? {body: body} : {}),
...(method=='PUT' ? {headers: jsonMimeType, body:JSON.stringify(body)} : {})
});
return response.json(); // parses response to JSON
}catch(err){
console.error(err);
return "{'status':'error'}";
}
}
// Calls our test function when we click the button
// afer validating that there's a file selected.
document.querySelector('#testme').addEventListener("click", ()=>{
let input = document.querySelector('input[type="file"]')
if (input.value){
testAPIs();
}else{
alert("please select an image file first");
}
});
})();
Here is an update PUT handler which should stop throwing "undefined .then of ...", note that updatePhoto needed to be renamed to updatedPhoto as well.
router.put('/:photoid', (req, res, next) => {
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
PhotoService.update(req.params.photoid, putdata).then((updatedPhoto) => {
res.status(200);
res.send(JSON.stringify(updatedPhoto));
}).catch((err) => {
res.status(404);
res.end();
});
});
And if you are using node 8+ you can use async/await. It simplifies the code and makes the problems easier to see:
router.put('/:photoid', async (req, res, next) => {
try {
console.log(`putting ${req.params.photoid}`);
let putdata = req.body;
const updatedPhoto = await PhotoService.update(req.params.photoid, putdata);
res.status(200);
res.send(JSON.stringify(updatedPhoto));
} catch (e) {
res.status(404);
res.end();
}
});

Don't find file when i upload image to server nodejs (use multer)

I have some problems with my server nodejs when i upload a image by multer.
https://github.com/expressjs/multer
When i go to folder uploads, i don't see my file uploaded!
My code:
app.use(multer(
{
dest: path.join(__dirname, 'uploads'),
inMemory: true,
includeEmptyFields: true,
onFileUploadStart: function (file, req, res) {
console.log('onFileUploadStart');
console.log(file);
},
onFileUploadData: function (file, data, req, res) {
console.log('onFileUploadData');
console.log(file);
},
onFileUploadComplete: function (file, req, res) {
console.log('onFileUploadComplete');
console.log(file);
},
limits: {
fieldNameSize: 999999999,
fieldSize: 999999999
},
onParseStart: function() {
console.log('Starting to parse request!');
},
onParseEnd: function(req, next) {
console.log('Done parsing!');
next();
},
onError: function(e, next) {
if (e) {
console.log(e.stack);
}
next();
}
}));
And route: (I received file from client)
router.post('/newapi/addimages',function(req,res){
try{
// fileName = file.name, file name passed by client. Not used here. We use the name auto-generated by Node
var file = req.files.file;
var filePath = file.path;
var lastIndex = filePath.lastIndexOf("/");
var tmpFileName = filePath.substr(lastIndex + 1);
var image = req.body;
image.fileName = tmpFileName;
return res.send({ok:'heyyou'});
}
catch(err){
console.log(err);
return res.send({ok:'heyyou'});
}
});
My result:
It's because you have the inMemory option set to true. This option makes the image stay in the process memory instead of piping it to the filesystem and is accessible through the req.files.file.buffer.
Change inMemory to false and you'll be good to go.
You don't have to set each option, and for your application you'd be good with most default values.
app.use(multer({ dest: path.join(__dirname, 'uploads') }));

Categories