Can't get the flutter posted image to the nodjes server - node.js

I want to get the image that have been posted to the nodejs flutter. I am using the bellow code in the flutter:
_openCameraPicture(BuildContext context) async {
var image = await ImagePicker().pickImage(source: ImageSource.camera);
setState(() async {
selectedImage = File(image!.path);
if (Network.isConnected) {
var request = http.MultipartRequest(
'POST', Uri.parse("${Network.serverUrl}/upload_image"));
request.fields['title'] = "testImage";
request.files.add(http.MultipartFile.fromBytes(
'picture', selectedImage!.readAsBytesSync(),
filename: selectedImage!.path.split("/").last));
var response =
await request.send().then((value) => {Navigator.pop(context)});
// if (response.statusCode == 200) {
// Do something ...
// }
}
});
}
In my nodejs server api I use:
router.post("/upload_image", PhoneInfoCtrl.apiUploadImage);
But I can not get the image and upload it to the server. My apiUploadImage is like:
static async apiUploadImage(req, res, next) {
try {
console.log(req);
res.sendStatus(200);
} catch (error) {
//res.status(500);
}
}
How may I extract the image from req? I tested some ways but was not possible. Is something wrong with my flutter code?

Solved by using multer in my router in nodejs.
const path = require('path');
const multer = require("multer");
const storage = multer.diskStorage({
destination : (req, file, cb) =>{
cb(null , "./public/images")
},
filename: (req, file, cb) =>{
console.log(file);
cb(null , Date.now() + path.extname(file.originalname));
},
});
then:
router.post("/upload_image", upload.single("picture"),myController.apiUploadImage);

Related

Unit testing code coverage for multer Node.js using Jest

I am trying to cover the lines and functions for code coverage of the simple multer file in Node.js but I am not getting where I am going wrong.
Here is the file:
fileUpload.js
const express = require("express");
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, callBack) => {
callBack(null, "uploads");
},
filename: (req, file, callBack) => {
callBack(null, `${file.originalname}`);
},
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype == "image/png" || file.mimetype == "image/jpg" || file.mimetype == "text/plain") {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Only .png, .jpg, .txt and .jpeg format allowed!'));
}
}
})
module.exports = {
upload,
express
};
fileUpload.test.js
const multer = require('multer')
const fileStorage = require("../file-storage");
jest.mock('multer', () => {
const multer = () => ({
diskStorage: () => {
return {
destination: (req, res, callBack) => {
callBack(null, 'uploads')
},
filename: (req, res, callBack) => {
req.body = {
userName: 'testUser'
}
req.files = [{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url',
buffer: Buffer.from('whatever'), // this is required since `formData` needs access to the buffer
}, ]
return callBack()
}
}
},
})
multer.diskStorage = () => jest.fn()
return multer
})
describe('65317652', () => {
const upload = fileStorage.upload
it('should pass', () => {
const storage = upload.diskStorage();
const uploadData = multer({
storage: storage
});
expect(uploadData).toBeTruthy();
});
});
I have searched plenty of blogs but didn't find any proper solution.
How to cover those lines?
That might not be the best way to test your module which uses multer (I don't personally know this library). However you could manage to reach your code in the following way.
Get rid of your mock since you want to cover the code from your file-storage.js not the code from your mock.
Perform all calls in order to reach the code you want to cover.
Here is how you could reach the 'destination' code from you file-storage.js:
const multer = require('multer')
const fileStorage = require("../file-storage");
// 1 - Get rid of mock since this is not what you want to cover
//
// jest.mock('multer', () => {
// const multer = () => ({
// diskStorage: () => {
// return {
// destination: (req, res, callBack) => {
// callBack(null, 'uploads')
// },
// filename: (req, res, callBack) => {
// req.body = {
// userName: 'testUser'
// }
// req.files = [{
// originalname: 'sample.name',
// mimetype: 'sample.type',
// path: 'sample.url',
// buffer: Buffer.from('whatever'), // this is required since `formData` needs access to the buffer
// },]
// return callBack()
// }
// }
// },
// })
// multer.diskStorage = () => jest.fn()
// return multer
// })
describe('65317652', () => {
const upload = fileStorage.upload
it('should pass', () => {
const storage = upload;
const multerRes = multer({
storage: storage
});
// 2 - Perform all calls in order to reach the code you want to cover.
//
expect(multerRes).toBeTruthy();
const diskStorageRes = multerRes.storage.storage
expect(diskStorageRes).toBeTruthy();
const getDestinationRes = diskStorageRes.getDestination()
expect(getDestinationRes).toBeTruthy();
});
});
There seem to be other more appropriate ways to test multer. See https://stackoverflow.com/a/58474936/6210975 for example.

Saving Images React To Nodejs

I am trying to upload an image from my front end to the backend but it it doesn't send the image in the request
It says that the formdata is empty and it says that there's no image found, where is the problem and how can I fix this error?
Here is the code from the Frontend made in react:
const [userInfo, setuserInfo] = useState({
file:[],
filepreview:null,
});
const handleInputChange = (event) => {
setuserInfo({
...userInfo,
file:event.target.files[0],
filepreview:URL.createObjectURL(event.target.files[0]),
});
}
const [isSucces, setSuccess] = useState(null);
const submit = async () =>{
const formdata = new FormData();
formdata.append('avatar', userInfo.file);
console.log(formdata)
Axios.post("http://localhost:4000/imageupload", formdata,{
headers: { "Content-Type": "multipart/form-data" }
})
.then(res => { // then print response status
console.warn(res);
if(res.data.success === 1){
setSuccess("Image upload successfully");
}
})
}
The code of the Backend made in NodeJS:
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
app.post('/imageupload', async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
let upload = multer({ storage: storage}).single('avatar');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields
if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
});
}catch (err) {console.log(err)}
})
Edit:
Multer is essentially a nodejs router,i.e. a function that can be pipelined between your HTTP request and HTTP response.
I think that you should first make multer analyze your HTTP content and to actually populate the req.file before actually evaluate express parsers do their job.
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
let upload = multer({ storage: storage});
app.post('/imageupload', upload.single('avatar'), async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
// req.file contains information of uploaded file
// req.body contains information of text fields
if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
}catch (err) {console.log(err)}
})
I am assuming that your upload code is working. Have you tried to read the HTTP request from your browser to see that the image has been correctly attached to the request?
Because probably the issue lies in the fact that you are not actually parsing the image.
const file = new File(userInfo.file, "avatar.png", {
type: 'image/png' // choose the appropriate
});
const formdata = new FormData();
formdata.append('avatar', file);
console.log(formdata)

Upload workds, but I can't access req.file in Node Express using Multer

The uploaded file is saved in the destination, but I can't access it in the express route.
Why might this be happening? It makes no sense to me...
EDIT: What I've noticed is that the console.log sometimes works, and sometimes doesn't... This is even weirder. If I upload a tiny file, it always logs. For larger ones, it randomly decides when to log. I wonder what the problem might be.
Client
async function uploadFile(file) {
console.log("file", file);
let formData = new FormData();
formData.append("file", file);
formData.append("recordUid", recordUid);
formData.append("fieldUid", fieldUid);
await fetchPostFile("/api/files", formData);
}
export async function fetchPostFile(url, formData) {
try {
let result = await (
await fetch(url, {
method: "POST",
withCredentials: true,
credentials: "include",
headers: {
Authorization: localStorage.getItem("token"),
},
body: formData,
})
).json();
return result;
} catch (err) {
return err;
}
}
Server
const express = require("express");
const router = express.Router();
const path = require("path");
const fs = require("fs");
const multer = require("multer");
const { getUidForTable } = require(`../utils.js`);
let filesFolderPath = path.join(__dirname, "../../../files/");
const storage = multer.diskStorage({
destination: filesFolderPath,
filename: async (req, file, cb) => {
cb(null, await getUidForTable("recordDataFile", 20));
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 1024 * 1024 * 10 }, // 10 mb
});
router.post("/api/files", upload.single("file"), async (req, res, next) => {
try {
console.log(req.file, req.body); // <------------ NOTHING IS LOGGED
res.status(200).send({ success: true });
} catch (err) {
next(err);
} finally {
req.connection.release();
}
});

Express Router - uploading to S3 and MongoDb

I'm trying to do the following in Node.js using express router, Multer-S3, Multer, AWS and Mongodb.
I want to:
1: Check if filetype is image, price is number etc (some kind of quality check)
2: If above true, upload image to S3 to get Image url
3: If Image Url was generated, upload to Mongodb, including the generated image url..
Trying with below code but can only get one of these to work at same time..
const express = require("express");
const router = express.Router();
const shopController = require("../controllers/shop");
router.post(
"/shop/create/:shopId",
shopController.creatingShop,
shopController.createShopItem
);
const ShopItem = require("../models/shopitem"); //Mongoose Schema
const multer = require("multer");
const fileview = multer().single("file1"); //Trying to use this to view file before uploading to S3
const uploader = require("../services/file-upload");
const singleUpload = uploader.single("file1"); //Using this to upload to S3
exports.createShopItem = (req, res, next) => {
fileview(req, res, function (err) {
const file = req.file;
const title = req.body.title;
const price = req.body.price;
const description = req.body.description;
const location = req.body.location;
const user = "OrreSnorre";
if (
file.mimetype != "image/jpeg" &&
file.mimetype != "image/jpg" &&
file.mimetype != "image/png"
) {
return next(new Error("invalid file type"));
}
if (file.size > 2500000) {
return next(new Error("Your image is to big. Maximum 2.5mb"));
}
next();
console.log(
"Here I want to add upload text to mongoDb... including URL from S3 after it is generated"
);
});
exports.creatingShop = (req, res, next) => {
singleUpload(req, res, function (err) {
console.log(req.file);
// res.json({ "image-url": req.file.location });
});
next();
};
Anyone got ideas? Or examples that work?
Best regards,
Oscar
There are 2 ways to do this, either you can use only multer or multer-s3.
For simplicity, I will show you the way using only multer.
Flow of processing as follow:
Multer process and save to local
You read from local, and upload to s3 using s3 SDK (You should explore how to remove the file after upload as well, but I wont clutter you with this logic here)
If upload is successful, you retrieve the URL and pass it to your MongoDB.
// Make "temp" directory as multer.diskStorage wont create folder
fs.mkdir('./temp', { recursive: true }, (err) => {
if (err) throw err;
});
const PORT = parseInt(process.argv[2]) || parseInt(process.env.PORT) || 3000;
// Multer
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './temp');
},
filename: function (req, file, cb) {
let extArray = file.mimetype.split('/');
let extension = extArray[extArray.length - 1];
cb(null, new Date().getTime() + '.' + extension);
},
});
const upload = multer({ storage: storage });
const endpoint = new AWS.Endpoint(AWS_S3_HOSTNAME);
const s3 = new AWS.S3({
endpoint,
accessKeyId: AWS_S3_ACCESSKEY_ID,
secretAccessKey: AWS_S3_SECRET_ACCESSKEY,
});
// Get the uploaded file in local here
const readFile = (path) =>
new Promise((resolve, reject) =>
fs.readFile(path, (err, buff) => {
if (null != err) reject(err);
else resolve(buff);
})
// Upload to AWS S3 here
const putObject = (file, buff, s3) =>
new Promise((resolve, reject) => {
const params = {
Bucket: AWS_S3_BUCKET_NAME,
Key: file.filename,
Body: buff,
ACL: 'public-read',
ContentType: file.mimetype,
ContentLength: file.size,
};
s3.putObject(params, (err, result) => {
if (null != err) reject(err);
else resolve(file.filename);
});
});
);
const mongoClient = new MongoClient(MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
app.post('/api/post', upload.single('imageFile'), async (req, res) => {
readFile(req.file.path)
.then((buff) =>
// Insert Image to S3 upon succesful read
putObject(req.file, buff, s3)
)
.then((results) => {
// build url of the resource upon successful insertion
const resourceURL = `https://${AWS_S3_BUCKET_NAME}.${AWS_S3_HOSTNAME}/${results}`;
const doc = {
comments,
title,
ts: new Date(),
image: resourceURL, // Your URL reference to image here
};
// Insert to your mongoDB
mongoClient
.db(MONGO_DB)
.collection(MONGO_COLLECTION)
.insertOne(doc)
.then((results) => {
// delete the temp file when no error from MONGO & AWS S3
fs.unlink(req.file.path, () => {});
// return the inserted object
res.status(200).json(results.ops[0]);
})
.catch((error) => {
console.error('Mongo insert error: ', error);
res.status(500);
res.json({ error });
});
})
.catch((error) => {
console.error('insert error: ', error);
res.status(500);
res.json({ error });
});
}

Set filname by id generated by mongoose using multer node js

I am new in Node js API and I'm trying to upload an Image using multer + express + mongoose + postman
CODE:
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'public/images/course');
},
filename: function (request, file, callback) {
return callback(null, file.originalname)
}
});
var upload = multer({storage : storage})
router.post('/course', upload.single('thumbnail'),async(req, res) => {
try{
var course = new Course({
name : req.body.name,
thumbnail : "placeholder" // set to path where file is uploaded
})
await course.save()
res.status(201).send(course)
}catch(e){
res.status(400).send(e)
}
})
I use postman to post request using form data and it creates an image with its originalFilename but i want the filename to be id generated by mongoose and i have seen somewhere that i can use filesystem for that but is there any way i can upload file after id is generated because when i do like this
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'public/images/course');
},
filename: function (request, file, callback) {
if (request.data) {
console.log(file)
// TODO: consider adding file type extension
fileExtension = file.originalname.split('.')[1]
return callback(null, `${request.path}-${request.data._id.toString()}.${fileExtension}`);
}
// fallback to the original name if you don't have a book attached to the request yet.
return callback(null, file.originalname)
}
});
var upload = multer({storage : storage}).single('thumbnail')
router.post('/course',(req, res) => {
console.log(req.body)
const course = new Course({
name : req.body.name,
thumbnail : req.body.name
})
//console.log(course)
req.data = course
//console.log(req.file)
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine.
})
})
Then i got request body empty.
Thanks in advance

Resources