File Upload React Native, Node JS, MongoDB, Multer, Grid FS - node.js

I am very new to React Native development. I am struggling from the past 2 days to crack the file/image upload with React Native to MongoDB(Grid FS). I literally read all the related forums but there is no luck. I read couple of forums and they gave a sample example but I wasn't succeeded. Here are the sample codes that I wrote.
Client JS (React Native):
import React, { Component } from "react";
import { View, Text, Image, Button, Platform } from "react-native";
import ImagePicker from "react-native-image-picker";
class ImagePickerComponent extends Component {
state = {
photo: null
};
handleChoosePhoto = () => {
const options = {
noData: true
};
ImagePicker.launchImageLibrary(options, response => {
if (response.uri) {
this.setState({ photo: response });
}
});
};
handleUploadPhoto = () => {
const { photo } = this.state;
const bodyJson = { userId: "123" };
console.log("PHOTO");
console.log(photo);
const data = new FormData();
data.append("name", "avatar");
data.append("file", {
uri: photo.uri,
type: photo.type,
name: photo.fileName
});
const config = {
method: "POST",
headers: {
Accept: "application/json"
// "Content-Type": "multipart/form-data"
},
body: data
};
fetch("http://localhost:3900/api/uploadFiles/upload", config)
.then(checkStatusAndGetJSONResponse => {
console.log("checkStatusAndGetJSONResponse");
console.log(checkStatusAndGetJSONResponse);
})
.catch(err => {
console.log(err);
});
};
createFormData = (photo, body) => {
console.log("PHOTO");
console.log(photo);
const data = new FormData();
data.append("photo", {
name: photo.fileName,
type: photo.type,
uri:
Platform.OS === "android" ? photo.uri : photo.uri.replace("file://", "")
});
Object.keys(body).forEach(key => {
data.append(key, body[key]);
});
return data;
};
render() {
const { photo } = this.state;
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
{photo && (
<React.Fragment>
<Image
source={{ uri: photo.uri }}
style={{ width: 300, height: 300 }}
/>
<Button title="Upload" onPress={this.handleUploadPhoto} />
</React.Fragment>
)}
<Button title="Choose Photo" onPress={this.handleChoosePhoto} />
</View>
);
}
}
export default ImagePickerComponent;
And below is the server JS file that handles to store the file in MongoDB with Multer.
const express = require("express");
const router = express();
const multer = require("multer");
const GridFsStorage = require("multer-gridfs-storage");
const path = require("path");
const crypto = require("crypto");
// Create storage engine
const storage = new GridFsStorage({
url: "mongodb://localhost/vidly",
file: (req, file) => {
console.log("In Storage: ");
console.log(file);
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "uploads"
};
console.log("fileInfo");
console.log(fileInfo);
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage }).single("file");
// #route POST /upload
// #desc Uploads file to DB
//upload.single("file"),
// router.post("/upload", upload.single("file"), (req, res) => {
// console.log("In Upload Function");
// console.log(req);
// res.json({ file: req.file });
// // res.redirect("/");
// });
router.post("/upload", upload, (req, res) => {
console.log(req);
console.log("file", req.file);
console.log("body", req.body);
res.status(200).json({
message: "success!"
});
});
router.get("/me", (req, res) => {
res.json("Hello!");
});
module.exports = router;
Also, Here is the server package.json files that I am using.
"dependencies": {
"#hapi/joi": "^15.0.3",
"body-parser": "^1.19.0",
"config": "^3.1.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"express-multipart-file-parser": "^0.1.2",
"gridfs-stream": "^1.1.1",
"mongoose": "^5.5.11",
"multer": "^1.4.1",
"multer-gridfs-storage": "^3.2.3",
"winston": "^3.2.1"
}
I am not getting any exception but the file is not storing into the mongoDB. Looks like Multer is not picking up the file from the request. My Server code is working when I test with POSTMAN but its not working with React Native.
I captured the Sample request & response from the react native debugger.
Also, Here are the logs from the server for failing request (From react Native).
route:
Route {
path: '/single',
stack:
[ Layer {
handle: [Function: multerMiddleware],
name: 'multerMiddleware',
params: undefined,
path: undefined,
keys: [],
regexp: /^\/?$/i,
method: 'post' },
Layer {
handle: [Function],
name: '<anonymous>',
params: undefined,
path: undefined,
keys: [],
regexp: /^\/?$/i,
method: 'post' } ],
methods: { post: true } },
**body:** [Object: null prototype] { photo: '[object Object]' },
__onFinished: null }
**undefined**
If we observe the request body we are getting an object.
Here is the server request that was captured through POSTMAN (Its a successful Request).
body: [Object: null prototype] {},
route:
Route {
path: '/upload',
stack:
[ Layer {
handle: [Function: multerMiddleware],
name: 'multerMiddleware',
params: undefined,
path: undefined,
keys: [],
regexp: { /^\/?$/i fast_star: false, fast_slash: false },
method: 'post' },
Layer {
handle: [Function],
name: '<anonymous>',
params: undefined,
path: undefined,
keys: [],
regexp: { /^\/?$/i fast_star: false, fast_slash: false },
method: 'post' } ],
methods: { post: true } },
file:
{ fieldname: 'file',
originalname: 'testAlert.html',
encoding: '7bit',
mimetype: 'text/html',
id: 5d1e3084e3aa4de0b8320773,
filename: 'e7d2080ddbe2cbf2ac7167d79b8ff0f2.html',
metadata: null,
bucketName: 'uploads',
chunkSize: 261120,
size: 148961,
md5: '4e68af2f75a34d2d7371f21544fe9b58',
uploadDate: 2019-07-04T16:59:48.602Z,
contentType: 'text/html' },
__onFinished: null }
If we observe both the requests file object is coming as a separate section through POSTMAN but not the case with react native. Can anyone please help me on this.? Why its not working with React-Native.? I stuck over here. Please help me on this.?
Thanks & Regards,
Amar.T

Related

React Native Axios cannot upload files to server FormData

Im implementing a function to upload titles, descriptions, and images to the server. Here is my snippet of Front-end code:
const [imageFiles, setImageFiles] = React.useState([]);
const callApi = async () => {
const formData = new FormData();
formData.append('title', 'test');
formData.append('content', 'tesst1');
imageFiles.forEach(imageFile => {
formData.append('files', imageFile);
});
const response = await axios({
method: 'post',
url: 'http://localhost:8080/api/complain',
headers: {
'Content-Type': 'multipart/form-data; ',
Authorization:
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
},
data: formData,
});
};
const openCamera = () => {
let imgList = [];
ImagePicker.openPicker({
multiple: true,
waitAnimationEnd: false,
includeExif: true,
compressImageQuality: 0.8,
maxFiles: 5,
includeBase64: true,
})
.then(images => {
images.map(image => {
imgList.push({
filename: image.filename,
path: image.path,
data: image.data,
type: image.mime,
height: image.height,
width: image.width,
});
});
setImageFiles(imgList);
})
.catch(err => {
console.log(err);
});
};
Here is the Back end code:
router.post(
"/complain",
authenticateToken,
upload.array("files"),
complainController.createComplain
);
However, when I console log req.files, it returns an empty array. I have tried different methods such as add transform request, using fetch from react native,... but none of them works. Please help me with this issue. Thank you guys.

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

upload image file from react to nodejs

This is react code
import React, { Component } from "react";
import Webcam from "react-webcam";
import * as faceapi from "face-api.js";
import { browserHistory } from "react-router";
import axios from "axios";
export default class WebCamPicure extends Component {
constructor() {
super();
this.state = {
selectedFile: null
};
fileSelectedHandler = (event) => {
console.log(event.target.files[0]);
this.setState({
selectedFile: event.target.files[0]
});
};
fileUploadHandler = () => {
const fd = new FormData();
fd.append("image", this.state.selectedFile, this.state.selectedFile.name);
fetch("http://localhost:5000/upload", {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
mode: "no-cors",
body: fd
});
};
render() {
return (
<div
className="App"
style={{
display: "flex",
flexDirection: "column",
alignItems: "center"
}}
>
<div class="upload">
<input type="file" onChange={this.fileSelectedHandler} />
<button onClick={this.fileUploadHandler}>upload</button>
</div>
</div>
);
}
}
this is node server code
const express = require("express");
var mysql = require("mysql");
const axios = require("axios");
var connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "expression_detection"
});
connection.connect((err) => {
if (!!err) {
console.log("error");
} else {
console.log("connected");
}
});
const app = express();
app.get("/api/customers", (req, res) => {
const customer = [
{ id: 1, firstname: "jhon", lastname: "doe" },
{ id: 2, firstname: "praveen", lastname: "smith" },
{ id: 3, firstname: "kumar", lastname: "swason" }
];
res.json(customer);
});
app.get("/", (req, res) => {
connection.query("SELECT * FROM individual_result", (error, row, fields) => {
if (!!error) {
console.log("Error in the query");
} else {
console.log("seccessful query");
console.log(row);
}
});
res.json("hello");
});
app.post("/upload", (req, file, res) => {
console.log("got it");
console.log(req);
// console.log(res);
});
const port = 5000;
app.listen(port, () => {
console.log("server started on port " + port);
});
I am trying upload image to nodejs server but i not able to recevie the upload file in server.I uploaded my code above please help me to solve this.now i need to get the uploaded file in server and store in database
I am trying upload image to nodejs server but i not able to recevie the upload file in server.I uploaded my code above please help me to solve this.now i need to get the uploaded file in server and store in database
You will need to configure a dedicated handler to work with multipart/form-data.
You can use multer.
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files.

ReactNative : variable for FormData() being logged as undefined in ReactNative application when i make an http request with a file

i have been trying to make a post request from my react native app on an android emulator but the object that i am sending in the body of the request is being vvalued as undefined,been trying alot to solve this issue but no success. Please help me
here is the code to my form in the app known as "API.js" its named so just for testing the API endpoints
import React, { Component } from "react";
import {
Text,
TextInput,
View,
TouchableHighlight,
StyleSheet,
Button,
FormData
} from "react-native";
import Permissions from "react-native-permissions";
import ImagePicker from "react-native-image-crop-picker";
import axios from "axios";
var styles = StyleSheet.create({});
var msg = "Select Image";
var data;
export default class API extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
price: "",
size: "",
description: "",
image: "",
popularity: ""
};
}
FormDataFunc() {
let form = new FormData();
form.append("name", this.state.name);
form.append("price", this.state.price);
form.append("size", this.state.size);
form.append("description", this.state.description);
form.append("image", this.state.image);
form.append("popularity", this.state.popularity);
return form;
return form;
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
Submit() {
axios({
method: "post",
url: "http://192.168.0.102:3000/products",
data: this.FormDataFunc,
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: this.FormDataFunc
})
.then(() => {
console.log("DONE!");
this.props.navigation.navigate("offersScreen");
})
.catch(err => {
console.log(err);
console.log(this.FormDataFunc);
});
}
componentDidMount() {
Permissions.check("photo").then(response => {
// Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
console.log(response);
});
}
render() {
const image = () => {
ImagePicker.openPicker({
multiple: false,
includeBase64: true
}).then(images => {
console.log(images);
this.setState({
images: { data: `\`${images.mime}\`;base64,\`${images.data}\`` }
});
console.log(this.state.images);
msg = "Selected";
});
};
return (
<View>
<TextInput placeholder="Name" name="name" />
<TextInput placeholder="Price" name="price" />
<TextInput placeholder="Size" name="size" />
<TextInput placeholder="Description" name="description" />
<TouchableHighlight onPress={image} name="image">
<Text>{msg}</Text>
</TouchableHighlight>
<TextInput placeholder="Popularity" name="popularity" />
<TouchableHighlight title="Submit" onPress={this.Submit}>
<Text>Send</Text>
</TouchableHighlight>
</View>
);
}
}
here is the code to my backend route "product.js" which recieves the request(node.js and express)
const express = require("express");
const router = express.Router();
const bodyParser = require("body-parser");
const path = require("path");
const cloudinary = require("cloudinary");
const mongoose = require("mongoose");
//Product Model
const product = require("../models/product").product;
router.use(bodyParser.json());
//GET route
router.get("/", (req, res) => {
product.find().then(product => res.json(product));
});
// POST route
cloudinary.config({
cloud_name: "cloud222",
api_key: "783935981748815",
api_secret: "uY47vBS1rI2x5jvFtnXQIjMMqU0"
});
router.post("/", (req, res) => {
//MISC//
let imageUrl;
console.log("starting");
//MISC//
//CLOUDINARY UPLOAD
cloudinary.v2.uploader.upload(req.body.image, (error, result) => {
if (error) {
console.log(error);
console.log(`${req.body.image}`);
} else {
imageUrl = result.secure_url;
//MONGO UPLOAD
var productv = {
name: req.body.name,
price: req.body.price,
size: req.body.size,
description: req.body.description,
image: imageUrl,
popularity: req.body.popularity
};
const productvar = new product(productv);
productvar
.save()
.then(product => console.log(product))
.then(product => res.json(product))
.catch(err => console.log(err));
}
});
//END//
});
module.exports = router;
the data is being logged as undefined and therefore the request doesnt get a response
I think the problem is that you have created a FormData and wanted to post it, but the headers you added is "application/json". You should change it:
headers: {
'content-type': 'multipart/form-data',
'Accept':'multipart/form-data',
},
Hope it works for you.
Problem solved
Had to use onChangeText = instead of onChange as onChange does not return a string

Upload File To Slack From Hapi

I am trying to upload a file that is being uploaded to my hapijs server directly to slack using the web api files.upload.
I get in return an error message {"ok":false,"error":"no_file_data"}.
The same code works if i upload a file that already in the storage using fs.createReadStream
Here is my code:
const Promise = require('bluebird');
const Joi = require('joi');
const Path = require('path');
const Boom = require('boom');
const Utils = require('../utils');
const Request = require('request');
exports.routes = Promise.coroutine(function*(server, options) {
server.route({
method: 'POST',
path: options.prefix,
config: {
tags: ['api', 'v1'],
payload: {
maxBytes: 2097152,
output: 'stream',
parse: true
},
plugins: {
'hapi-swagger': {
payloadType: 'form'
}
},
validate: {
payload: Joi.object({
cv: Joi.object({ pipe: Joi.func().required() }).required().unknown().description('CV file').meta({ swaggerType: 'file' })
})
},
response: {
emptyStatusCode: 204,
schema: false
},
handler: Utils.coHandler(function*(request, reply) {
const supportedFiles = ['docx', 'doc', 'pdf', 'pages'];
const ext = Path.extname(request.payload.cv.hapi.filename).substr(1);
if (!supportedFiles.filter((supExt) => supExt === ext).length) {
return reply(Boom.badRequest('Unsupported file type'));
}
Request.post({
url: 'https://slack.com/api/files.upload',
formData: {
token: 'XXXX',
filename: `${request.payload.name} - CV.${ext}`,
file: request.payload.cv,
channels: 'XXXX'
}
}, (err, res, body) => {
console.log(body);
});
reply();
})
}
});
});

Resources