uploading image to nodejs backend (express multer ) from expo app - node.js

I have a backend and a create ticket route, in my web react app the image upload works fine but in react native it was not working
here is my react native pickimage code
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.cancelled) {
setImage(result.uri);
}
};
it was only set the file path to setImage and after it wasn't get uploaded
the request code
here I make the request but everything gets saved on the database except the image
const sendticket = async (title, description, image) => {
setIsLoading(true);
if (title === "" || description === "") {
Alert.alert("Error", "Please fill all the fields");
return;
}
const url = `${BASE_URL}/ticket/`;
try {
const formData = new FormData();
formData.append("title", title);
formData.append("description", description);
formData.append("image", image);
formData.append("creator", userInfo.userId);
const response = await fetch(url, {
method: "POST",
body: formData,
headers: {
Authorization: "Bearer " + userInfo.token,
},
});
const data = await response.json();
if (response.status === 201) {
Alert.alert("Success", "Ticket " + data.Ticket.number + " created");
} else {
console.log(response.status);
console.log(response.statusText);
Alert.alert("Error", "Something went wrong");
}
} catch (error) {
console.log(error);
}
setIsLoading(false);
};
there is the route and multer file upload BACKEND
route.post
router.post(
"/",
wenauppload.single("image"),
[check("title").not().isEmpty(), check("description").isLength({ min: 5 })],
ticketcontroller.createTicket
);
file-upload.js
const multer = require("multer");
const uuid = require("uuid");
const MIME_TYPE_MAP = {
"image/png": "png",
"image/jpeg": "jpeg",
"image/jpg": "jpg",
};
const fileUpload = multer({
limits: 1500000,
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "uploads/images");
},
filename: (req, file, cb) => {
const ext = MIME_TYPE_MAP[file.mimetype];
cb(null, uuid.v4() + "." + ext);
},
}),
fileFilter: (req, file, cb) => {
const isValid = !!MIME_TYPE_MAP[file.mimetype];
let error = isValid ? null : new Error("Invalid mime type!");
cb(error, isValid);
},
});
module.exports = fileUpload;

Related

Multer with node.js / react-native not working

I'm creating an application with reaction-native, and I'm using an image picker to select an image and click the button to create a part that sends the image to the node.js server.
However, in the process of uploading an image, other additional information is normally stored in mysql, but images are not stored in the upload folder.
Multer version 1.4.2.
Node.js version 16.12.0
in react-native code ( data to node.js)
onPress={() => {
if (this.state.image === null) {
alert("이미지를 넣어주세요");
} else {
Alert.alert(
"구인 공고를 등록할까요?",
"등록후, 수정할 수 없으니 꼼꼼히 확인 부탁~!!",
[
{
text: "Cancel",
onPress: () => alert("취소하였습니다."),
style: "cancel"
},
{
text: "OK",
onPress: async () => {
const formData = new FormData();
formData.append("db_title", this.state.title);
formData.append("db_wtype", this.state.type);
formData.append("db_sdate", this.state.start);
formData.append("db_edate", this.state.end);
formData.append("db_money", this.state.money);
formData.append(
"db_address",
this.state.address
);
formData.append(
"db_description",
this.state.addition
);
formData.append("file", this.state.image);
formData.append("db_stime", "9");
formData.append("db_etime", "18");
formData.append("db_smin", "00");
formData.append("db_emin", "30");
await AsyncStorage.getItem("pubKey").then(
(pubKey) => {
formData.append("db_pubkey", pubKey);
}
);
const {
data: { result }
} = await axios.post(
"http://127.0.0.1:4000/upload",
formData
);
console.log(result);
alert(result);
this.props.navigation.navigate("Announce");
}
}
],
{ cancelable: false }
);
}
}}
in my node server code
const multer = require('multer');
const _storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/upload')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: _storage });
router.post("/", upload.single("file"), function (req, res) {
console.log(req.body);
console.log(req.body.file);
Article.create({
db_title: req.body.db_title,
db_wtype: req.body.db_wtype,
db_sdate: req.body.db_sdate,
db_edate: req.body.db_edate,
db_stime: req.body.db_stime,
db_etime: req.body.db_etime,
db_smin: req.body.db_smin,
db_emin: req.body.db_emin,
db_pubkey: req.body.db_pubkey,
db_money: req.body.db_money,
db_address: req.body.db_address,
db_description: req.body.db_description,
db_img: req.body.file
})
.then(result => {
console.log("result : " + result);
res.status(201).json({ result: "공고가 등록 되었습니다." });
})
.catch(err => {
console.error("err : " + err);
});
});
module.exports = router;
this is node.js console log
edit image picker (this.state.image)
_pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3]
});
console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ");
console.log(
result
);
console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ");
if (!result.cancelled) {
this.setState({ image: result.uri });
}
};
You need to use the path made by multer:
change:
db_img: req.body.file
to
db_img: req.file.path

Upload a profile pic with Reactjs and Nodejs to MongoDb

I am trying to let the user update their profile with their own avatar but for some reason, it doesn't work. I am sending a FormData from the front-end and catch it with nodeJs before storing it to MongoDB. user has 3 options to update: name, about, avatar. Whenever I try to update the name and about it works just fine but when I am uploading an avatar I get a 500 error. Can you guys take a look? FYI I am a begginer.
Here is my code:
FRONT-END
const handleFileInputChange = (e) => {
const file = e.target.files[0];
previewFile(file);
setUser({
...user,
avatar: file,
});
};
const onSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('name', user.name);
formData.append('about', user.about);
formData.append('avatar', user.avatar);
editUserProfile(formData); // external axios.patch f.
};
const editUserProfile = async (formData) => {
try {
await axios.patch('api/v1/users/me', formData, {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
dispatch({
type: EDIT_USER,
});
} catch (err) {
console.log(err);
}
};
<form onSubmit={onSubmit} encType="multipart/form-data">
<input
// accept="image/*"
accept=".png, .jpg, .jpeg"
type="file"
name="avatar"
// value={fileInputState}
onChange={handleFileInputChange}
style={{ display: 'none' }}
id="icon-button-file"
/>
...
BACK-END
router.patch('api/v1/users/me', protect, upload.single('avatar'), getMe, editUser = async (req, res) => {
try {
const { name, about } = req.body;
const profileFileds = {};
if (name) profileFileds.name = name;
if (about) profileFileds.about = about;
if (req.file) profileFileds.avatar = req.file.filename;
const user = await User.findByIdAndUpdate(req.params.id, profileFileds, {
new: true,
runValidators: true,
});
if (!user) {
return next(
new custom error...
);
}
res.status(200).json({
status: 'success',
data: {
user,
},
});
} catch (err) {
console.log(err) error 400 ...
}
}););
Sorry guys if it's a long code and I really appreciate it, I am struggling 2 days now and can't figure it out
//MULTER CONFIG just in case but it shouldn't be a problem with it
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/images');
},
filename: function (req, file, cb) {
cb(null, uuidv4() + '-' + Date.now() + path.extname(file.originalname));
},
});
const fileFilter = (req, file, cb) => {
const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if (allowedFileTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 2,
},
fileFilter: fileFilter,
});

React Native uploading multiple images with fetch to node js server with express and multer

I am trying to upload multiple images to my nodejs server where i am using multer to parse form-data,
but the problem is, when i am trying to upload images through postman it gets successfully upload but with react native fetch api it didn't work.
Here is my code:
React Native:
import React from "react";
import { View, Text, Button } from "react-native";
export default function imageUpload(props) {
function upload() {
const photo1 = {
uri: "https://html5box.com/html5gallery/images/Swan_1024.jpg",
type: "image/jpeg",
name: "photo1.jpg",
};
const photo2 = {
uri:
"https://www.canva.com/wp-content/themes/canvaabout/img/colorPalette/image4.jpg",
type: "image/jpeg",
name: "photo2.jpg",
};
const photos = [photo1, photo2];
const form = new FormData();
for (let photo in photos) {
form.append("image", photos[photo]);
}
console.log(form);
fetch("http://192.168.31.208:3000/uploads", {
body: form,
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
// Accept: "application/x-www-form-urlencoded",
},
})
.then((response) => response.json())
.then((responseData) => {
console.log("Response:" + responseData);
})
.catch((error) => {
console.log(error);
});
}
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Image Upload</Text>
<Button title="Test" onPress={upload} />
</View>
);
}
Server Code:
const express = require("express");
const http = require("http");
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: "./uploads",
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 52428800 },
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
},
}).array("image");
function checkFileType(file, cb) {
const fileType = /jpeg|jpg|png|gif/;
const extname = fileType.test(path.extname(file.originalname).toLowerCase());
const mimeType = fileType.test(file.mimetype);
if (extname && mimeType) {
return cb(null, true);
} else {
cb("Error: FILE_SHOULD_BE_TYPE_IMAGE");
}
}
// Initialise app
const app = express();
app.use(express.static("./uploads"));
app.post("/uploads", (req, res) => {
upload(req, res, (err) => {
if (err) {
res.status(400).json({
error: err,
});
} else {
console.log(req);
res.status(200).json({
// name: req.body.name,
// image: req.file,
message: "Testing",
});
}
});
});
app.get("/upload", (req, res, next) => {
res.status(200).json({
message: "TestComplete",
});
});
const port = 3000;
app.listen(port, () => {
console.log(`Server started on port number: ${port}`);
});
Console Output Frontend:
FormData {
"_parts": Array [
Array [
"image",
Object {
"name": "photo1.jpg",
"type": "image/jpeg",
"uri": "https://html5box.com/html5gallery/images/Swan_1024.jpg",
},
],
Array [
"image",
Object {
"name": "photo2.jpg",
"type": "image/jpeg",
"uri": "https://www.canva.com/wp-content/themes/canvaabout/img/colorPalette/image4.jpg",
},
],
],
}
Network request failed
- node_modules\whatwg-fetch\dist\fetch.umd.js:473:29 in xhr.onerror
- node_modules\event-target-shim\dist\event-target-shim.js:818:39 in EventTarget.prototype.dispatchEvent
- node_modules\react-native\Libraries\Network\XMLHttpRequest.js:574:29 in setReadyState
- node_modules\react-native\Libraries\Network\XMLHttpRequest.js:388:25 in __didCompleteResponse
- node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:190:12 in emit
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:436:47 in __callFunction
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:26 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:110:17 in __guard$argument_0
* [native code]:null in callFunctionReturnFlushedQueue
Thanks for any help
If you are trying to upload an image from mobile (Android/iOS) you can't pass it as URL. You should send a local file path/uri

Unable to upload image/video files from react-native to nodejs

I am using expo-image-picker in react-native to pick image/video files and multer in nodejs as middleware to download files in directory /public/upload. When i am uploading file along with other parameters from react-native, multer is unable to detect a file present in req.body and hence not downloading any file.
Here is my react-native code using axios
pickImage = async () => {
try {
let options = {
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 1,
// base64:true
}
let result = await ImagePicker.launchImageLibraryAsync(options)
if (!result.cancelled) {
this.setState({ content: result })
}
} catch (E) {
console.log("error in picking image:", E)
}
}
createFormData = (response) => {
const photo = {
uri: response.uri,
type: response.type,
name: "my-img.jpg",
};
const form = new FormData();
form.append('acivityFile',photo);
return form;
};
handleSubmit = async () => {
if (this.state.content) {
const formData = this.createFormData(this.state.content)
console.log("form data:", formData)
try {
const res = await axios.post('http://393ad751391b.ngrok.io/activities',
{
title: "This is the title",
description: "This is a description",
eventType: "LOST & FOUND",
file: formData
},
{
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
},
)
console.log("res:", res.data);
} catch (err) {
console.log("err in post axios:",err)
}
}
}
Here is my route file handling http requests in server-side
const express = require('express');
const Upload = require('./../utils/multerSetup');
const activityController = require('../Controllers/activityController');
const router = express.Router();
router
.route('/')
.get(activityController.getAllActivities)
.post(
Upload.single('activityFile'),
activityController.addActivity
);
Here is my multerSetup.js file in server-side
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/');
},
filename: function (req, file, cb) {
const ext = file.mimetype.split('/')[1];
cb(null, file.fieldname + '-' + Date.now() + '.' + ext);
},
});
const upload = multer({ storage });
module.exports = upload;
Here is my activityController.js file in server-side
const Activity = require('./../modals/activityModel');
const User = require('./../modals/user');
exports.getActivity = async (req, res, next) => {
console.log('here');
const activity = await Activity.findById(req.params.id);
res.status(200).json({
status: 'success',
data: {
activity,
},
});
};
exports.addActivity = async (req, res, next) => {
if (req.file) {
let file = {
Ftype: req.file.mimetype.split('/')[0],
name: req.file.filename,
};
req.body.file = file;
}
if (!req.body.location) {
req.body.location = {
coordinates: ['77.206612', '28.524578'],
};
}
if (req.body.votes) {
req.body.votes.diff = req.body.votes.up - req.body.votes.down;
}
req.body.creator = "12345" || "req.userId";
const activity = await Activity.create(req.body);
res.status(201).json({
status: 'success',
data: {
activity,
},
});
};
Also when Content-type:'multipart/form-data, then server console throws Error: Multipart:Boundary not found. When i use Content-type:'application/json', then multer does not work.
I just want to know what is the correct way of uploading files with additional parameters from react-native to nodejs multer. Any suggestions would be a great help!

How to upload images from react native to nodejs?

I'm trying to upload an image with expo picker image to a nodejs server.
The problem is I never receive the image. I tried so many things I'm desesperate :(
Here is my code :
React-Native
postImage = async (image) => {
const photo = {
uri: image.uri,
type: "image/jpg",
name: "photo.jpg",
};
const form = new FormData();
form.append("test", photo);
axios.post(
url,
{
body: form,
headers: {
'Content-Type': 'image/jpeg',
}
}
)
.then((responseData) => {
console.log("Succes "+ responseData)
})
.catch((error) => {
console.log("ERROR " + error)
});
}
pickImage = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
// mediaTypes: ImagePicker.MediaTypeOptions.All,
// allowsEditing: true,
// aspect: [4, 3],
quality: 1
});
if (!result.cancelled) {
try {
await this.postImage(result);
} catch (e) {
console.log(e);
}
this.setState({ image: result.uri });
}
};
It always works.
And here the nodejs code
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const multer = require('multer');
const fs = require("fs");
const app = express();
const upload = multer({
dest: "upload/",
});
// app.use(upload.single("test"));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cors());
app.listen(8080, () => {
console.log("running ...")
})
app.post("/upload", upload.single("photo.jpg"), async (req, res) => {
console.log("body =>", req.body);
console.log('files => ', req.files);
console.log("file =>", req.file);
// const oldpath = req.body.;
// const newpath = '/Users/mperrin/test/test-native/test-upload-photo/server/lol.jpg';
// fs.rename(oldpath, newpath, (err) => {
// if (err) {
// throw err;
// }
// res.write('File uploaded and moved!');
// res.sendStatus(200);
// });
res.sendStatus(200);
});
I always see this in the console and I don't know what to do with that ...
body => {
body: { _parts: [ [Array] ] },
headers: { 'Content-Type': 'image/jpeg' }
}
At the moment only the folder "upload" is created.
I don't know where I can get the files, I guess I'm really missing something but I don't know what.
Thanks for help guys !
I've never used multer before but after a quick review of the docs it looks like you need to have the same name in the headers as you're expecting in the node side post
Right now, in your header you have
name: 'photo.jpg'
and the following in your node post
upload.single("test")
Your post is looking for something with the name 'test' not 'photo.jpg' and you're sending 'photo.jpg'
Try it out and let me know how it goes.
Edit: My mistake, you may have add
name: "test"
to the headers here instead of in the photo object:
axios.post(
url,
{
body: form,
headers: {
'Content-Type': 'image/jpeg',
}
})

Resources