routes.js
const storage = multer.diskStorage({
destination: "./Upload/Images",
filename: (req, file, cb) => {
return cb(
null,
//file.originalname
`${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`
//`${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`
);
},
});
const upload = multer({
storage: storage,
limits: {
fileSize: 900000,
},
});
petRoute.route("/addpets").post(upload.single("imgforsell"), (req, res) => {
console.log(req.file);
var img = fs.readFileSync(req.file.path);
//var img = fs.readFileSync(req.body.path);
var encode_image = img.toString("base64");
const pet = new petModel({
name: req.body.name,
title: req.body.title,
contact: req.body.contact,
price: req.body.price,
description: req.body.description,
selectedcat: req.body.selectedcat,
selectedcity: req.body.selectedcity,
imgforsell: Buffer.from(encode_image, "base64"),
//imgforsell:req.body.imgforsell,
contentType: req.file.mimetype,
});
pet
.save() // img
.then((img) => {
//img.id
res.json(img.id);
})
.catch((err) => {
//remove return and curly braces
return res.json(err);
});
});
I am trying to build a mern stack application using React-native expo.In this application I am trying to store an image as buffer data in mongo database which stores image name as binary format mongodb and I mage is being upload to static folder in root folder.This above code work fine with Postman but when I try to add data with Physical device it give two error on backend:
undefined TypeError: Cannot read properties of undefined (reading 'path')
on Frontend: Request failed with status code 500
I am using axios to post data
frontend.js
import {
View,
Text,
TextInput,
Image,
TouchableOpacity,
StyleSheet,
ScrollView,
Picker,
Platform,
Alert,
input
} from "react-native";
//const bodyParser = require('body-parser')
//router.use(bodyParser.json());
//router.use(bodyParser.urlencoded({ extended: true }));
import React, { Component } from "react";
import axios from "axios";
import * as ImagePicker from 'expo-image-picker';
import ImagePickerExample from "../components/CameraFunc";
import Constants from "expo-constants";
import * as FileSystem from 'expo-file-system';
export default class Sellnow extends Component {
constructor(props) {
super(props);
this.onChangePetName = this.onChangePetName.bind(this);
this.onChangePetTitle = this.onChangePetTitle.bind(this);
this.onChangePetContact = this.onChangePetContact.bind(this);
this.onChangePetPrice = this.onChangePetPrice.bind(this);
this.onChangePetDescription = this.onChangePetDescription.bind(this);
this.onValueChangeCat= this.onValueChangeCat.bind(this);
this.onValueChangeCity= this.onValueChangeCity.bind(this);
this.onFileChange = this.onFileChange.bind(this);
// this.pickImage = this.pickImage.bind(this);
this.onSubmit = this.onSubmit.bind(this);
// State
this.state = {
name: "",
title: "",
contact: "",
price: "",
description: "",
selectedcat:"",
selectedcity:"",
imgforsell:"",
//collection categories
category: [
{
itemName: "Select Category...."
},
{
itemName: "Pets Food"
},
{
itemName: "Pets Products"
},
{
itemName: "Pets Accessories"
}
],
// cities category
cityCategory:[
{
itemName: "Select City...."
},
{
itemName: "Islamabad"
},
{
itemName: "Rawalpindi"
},
{
itemName: "Lahore"
},
{
itemName: "Peshawar"
},
{
itemName: "Karachi"
},
{
itemName: "Quetta"
}
]
};
}
/*componentDidMount() {
axios.get('http://localhost:3000/PetsBazar/pets/' )
.then(res => {
this.setState({
name: res.data.name,
title: res.data.title,
contact: res.data.contact
});
})
.catch((error) => {
console.log(error);
})
}*/
onChangePetName(e) {
this.setState({ name: e.target.value });
}
onChangePetTitle(e) {
this.setState({ title: e.target.value });
}
onChangePetContact(e) {
this.setState({ contact: e.target.value });
}
onChangePetPrice(e) {
this.setState({ price: e.target.value });
}
onChangePetDescription(e) {
this.setState({ description: e.target.value });
}
// categories function
onValueChangeCat(e) {
this.setState({ selectedcat: e.targetvalue })
}
// city function
onValueChangeCity(e) {
this.setState({ selectedcity: e.targetvalue })
}
onFileChange(e) {
this.setState({ imgforsell: e.target.files[0] })}
// uploading Image
_getPhotoLibrary = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
base64: true,
exif: true,
aspect: [4, 3]
});
if (!result.cancelled) {
this.setState({ imgforsell: result });
}
this.props.navigation.setParams({
imgforsell: this.state.imgforsell
});
};
onSubmit (e) {
e.preventDefault();
/*const petsObject = {
name: this.state.name,
title: this.state.title,
contact: this.state.contact,
price: this.state.price,
description: this.state.description,
selectedcat:this.state.selectedcat,
selectedcity:this.state.selectedcity,
imgforsell:this.state.imgforsell
};
*/
const formData = new FormData();
/*formData.append( 'imgforsell', {
// name: new Date() + '_profile',
uri: this.state.imgforsell,
type: 'image/jpg',
});*/
formData.append("name", this.state.name);
formData.append("title", this.state.title);
formData.append("contact", this.state.contact);
formData.append("price", this.state.price);
formData.append("description", this.state.description);
formData.append("selectedcat", this.state.selectedcat);
formData.append("selectedcity", this.state.selectedcity);
formData.append("imgforsell", this.state.imgforsell);
fetch(
`http://${
Platform.OS === "android" ? "192.168.10.11" : "localhost"
}:4000/pets/addpets`,
{
method: "POST",
body: formData,
}
)
.then((res) => {
if (!res.ok) {
return Promise.reject(res);
}
return res.json();
})
.then((data) => {
console.log(data);
})
.catch((err) => {
console.error(err);
})
.finally(() => {
this.setState({
name: "",
title: "",
contact: "",
price: "",
description: "",
selectedcat: "",
selectedcity: "",
imgforsell: "",
});
});
}
render() {
const {imgforsell} = this.state
return (
<View>
<ScrollView
nestedScrollEnabled={true}
showsVerticalScrollIndicator={false}
>
<View style={styles.container}>
<View style={styles.formContainer}>
<Text style={styles.conText}>Please Fill the Below Form </Text>
<View style={styles.borderForm}>
<Text style={styles.formText}>Your Name</Text>
<TextInput
style={styles.formInput}
multiline
placeholder="Please Enter Your Name"
maxLength={15}
value={this.state.name}
onChange={this.onChangePetName}
blurOnSubmit={true}
onChangeText={(name) => this.setState({ name })}
/>
<Text style={styles.formText}>Category</Text>
{ /*<CategoryDropList />*/ }
<View style={styles.viewStyle}>
<Picker
itemStyle={styles.itemStyle}
mode="dropdown"
style={styles.pickerStyle}
selectedValue={this.state.selectedcat}
// onValueChange={this.onValueChangeCat.bind(this)}
//onValueChange={(selectedcat)=>this.setState({selectedcat})}
onValueChange={(itemValue,itemIndex)=> this.setState({selectedcat:itemValue})}
>
{this.state.category.map((item, index) => (
<Picker.Item
color="black"
label={item.itemName}
value={item.itemName}
index={index}
/>
))}
</Picker>
</View>
<Text style={styles.formText}>Pet/Product Title</Text>
<TextInput
style={styles.formInput}
placeholder="Enter Product Title"
maxLength={15}
value={this.state.title}
blurOnSubmit={true}
onChange={this.onChangePetTitle}
onChangeText={(title) => this.setState({ title })}
/>
<Text style={styles.formText}>City</Text>
{/*<CityDropList />*/}
<View style={styles.viewStyle}>
<Picker
itemStyle={styles.itemStyle}
mode="dropdown"
style={styles.pickerStyle}
selectedValue={this.state.selectedcity}
onValueChange={(itemValue,itemIndex)=> this.setState({selectedcity:itemValue})}
>
{this.state.cityCategory.map((item, index) => (
<Picker.Item
color="black"
label={item.itemName}
value={item.itemName}
index={index}
/>
))}
</Picker>
</View>
<Text style={styles.formText}> Contact Number </Text>
<TextInput
style={styles.formInput}
placeholder="Phone Number"
inputType="number"
maxLength={11}
keyboardType="number-pad"
blurOnSubmit={true}
value={this.state.contact}
onChange={this.onChangePetContact}
onChangeText={(contact) => this.setState({ contact })}
/>
<Text style={styles.formText}>Price</Text>
<TextInput
style={styles.formInput}
multiline
placeholder="Enter Price"
inputType="number"
keyboardType="number-pad"
blurOnSubmit={true}
maxLength={7}
value={this.state.price}
onChange={this.onChangePetPrice}
onChangeText={(price) => this.setState({ price })}
/>
<Text style={styles.formText}>Image of Product</Text>
{/*<ImagePickerExample />*/}
<TouchableOpacity style={styles.btn} onPress={this._getPhotoLibrary.bind(this)}>
<Text style={styles.btnTxt}> Choose File</Text>
</TouchableOpacity>
{imgforsell ? (
<Image source={{ uri: imgforsell.uri }} style={styles.uploadimgstyle} />
) : (
<View/>
)}
<Text style={styles.formText}>
Description(Optional max 150 words)
</Text>
<TextInput
style={styles.descriptionInput}
multiline
placeholder="Describe your product"
maxLength={150}
blurOnSubmit={true}
value={this.state.description}
onChange={this.onChangePetDescription}
onChangeText={(description) => this.setState({ description })}
/>
<TouchableOpacity style={styles.btn} onPress={this.onSubmit}>
<Text style={styles.btnTxt}>Submit</Text>
</TouchableOpacity>
</View>
</View>
</View>
</ScrollView>
</View>
);
}
}
//export default withRouter(Sellnow);
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
height: "auto",
width: "auto",
},
sellText: {
fontSize: 35,
fontWeight: "bold",
textAlign: "center",
},
formContainer: {
backgroundColor: "#ff9933",
flex: 1,
flexDirection: "column",
alignSelf: "center",
},
conText: {
fontSize: 25,
fontWeight: "bold",
textAlign: "left",
marginVertical: 10,
marginHorizontal: 15,
},
formInput: {
//flex:1,
height: 50,
// marginLeft:7,
//marginRight:7,
fontSize: 18,
margin: 10,
width: 350,
borderWidth: 1,
borderColor: "black",
backgroundColor: "white",
textAlign: "left",
borderRadius: 10,
padding: 10,
},
formText: {
fontSize: 20,
fontWeight: "bold",
textAlign: "left",
margin: 10,
},
descriptionInput: {
height: 80,
margin: 10,
width: 340,
borderWidth: 1,
borderColor: "black",
backgroundColor: "white",
textAlign: "left",
borderRadius: 20,
padding: 10,
},
borderForm: {
alignSelf: "center",
borderWidth: 1,
borderColor: "#FF642E",
margin: 7,
height: "auto",
width: "auto",
},
btn: {
margin: 20,
height: 35,
width: 120,
backgroundColor: "#FF642E",
borderRadius: 20,
alignSelf: "center",
},
btnTxt: {
fontSize: 20,
fontWeight: "bold",
textAlign: "center",
color: "white",
margin: 5,
},
dropdown: {
backgroundColor: "white",
borderWidth: 1,
borderColor: "black",
},
dropdownContainer: {
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
alignSelf: "center",
justifyContent: "center",
paddingTop: Constants.statusBarHeight,
backgroundColor: "#ff9933",
padding: 8,
},
itemStyle: {
fontSize: 10,
fontFamily: "Roboto-Regular",
color: "black",
},
pickerStyle: {
width: "73%",
height: 40,
color: "black",
fontSize: 14,
fontFamily: "Roboto-Regular",
//marginLeft:-100,
// alignItems:"flex-start"
},
textStyle: {
fontSize: 14,
fontFamily: "Roboto-Regular",
textAlign:'left'
},
viewStyle: {
// flex: 1,
alignSelf: "center",
flexDirection: "row",
width: "140%",
justifyContent: "space-between",
alignItems: "flex-start",
borderWidth:1,
height:'5%',
backgroundColor:'white',
borderRadius:10,
margin:7
},
uploadimgstyle:{
width: 100,
height: 100,
margin:5,
resizeMode:'cover',
alignSelf:'center'
}
});
The way you're calling Axios is the problem. The signature for the post method is
axios.post(url[, data[, config]])
With your code, that's
axios.post(
/* url */ Platform.OS === "android" ? "http://192.168.10.11:4000/pets/addpets" : "http://localhost:4000/pets/addpets",
/* data */ petsObject,
/* config */ formData
)
so you're passing the FormData
as the config
object.
You cannot mix application/json
and multipart/form-data
in the same request. Instead, you need to build up FormData
with all the parameters you need. When uploading a file, you also need to append the File
instance and not an object with uri
and type
properties.
const formData = new FormData();
// append the File
formData.append("imgforsell", this.state.imgforsell);
// append other data
formData.append("name", this.state.name);
formData.append("title", this.state.title);
// etc...
axios
.post(
`http://${
Platform.OS === "android" ? "192.168.10.11" : "localhost"
}:4000/pets/addpets`,
formData
)
.then(({ data }) => {
console.log(data);
})
.catch((err) => {
console.error(err.toJSON());
// res.status(500).json(err) 👈 don't do this, it's not Express
})
.finally(() => {
this.setState({
name: "",
title: "",
contact: "",
price: "",
description: "",
selectedcat: "",
selectedcity: "",
imgforsell: "",
});
});
If Axios doesn't work (because I've seen patchy reports about file uploads in React Native), you can substitute it with fetch
fetch(
`http://${
Platform.OS === "android" ? "192.168.10.11" : "localhost"
}:4000/pets/addpets`,
{
method: "POST",
body: formData,
}
)
.then((res) => {
if (!res.ok) {
return Promise.reject(res);
}
return res.json();
})
.then((data) => {
console.log(data);
})
.catch((err) => {
console.error(err);
})
.finally(() => {
this.setState({
name: "",
title: "",
contact: "",
price: "",
description: "",
selectedcat: "",
selectedcity: "",
imgforsell: "",
});
});