Uploading Files from React Native to a NodeJs Server using `fs.createWriteStream()`
leveraging the power of streams using nodejs.
You wanna hear a story ?
- Are you stuck while uploading a file from React Native to a server ?
- Do you want a
Progress Indicator
also ? - Do you also want to create a stream to receive the data chunk by chunk in your server ?
Well, then this story is for you.... I am writing my learnings in this blog post, I hope it server you well.
Configuring the React Native Client
- First install react native fs using npm
npm install react-native-fs
Mistakes I made :
- I used the full file path i.e. starting with
file://
, don't do that. Rather use the relative filepath. - Didn't carefully craft my request headers. Do that carefully.
- Didn't dive deep into
filetype
of the file to be uploaded. You can do that using react-native-file-type
Below is a small script that denotes the type of syntax you should follow, taken directly from the README.md
of the concerned dependency.
let filepath = '/data/user/0/com.<app-name>/<path to file>' // always use this path, otherwise check path using "console.log(RNFS.DocumentDirectoryPath);" .Other paths might lead to error.
let files = {{
name: 'file_name',
filename: filename,
filepath: filepath,
filetype: 'video/mp4',
}];
let uploadUrl = 'https://<domain-name>/<api route>/';
RNFS.uploadFiles({
toUrl: uploadUrl,
method: 'POST',
files: files,
headers: {
Accept: 'application/json',
Authorization:
'Bearer <xxx-bearer-token for auth purposed>',
},
begin: uploadBegin,
progress: uploadProgress,
}).promise.then(response => {
if (response.statusCode == 200) {
console.log('FILES UPLOADED!');
} else {
console.log('SERVER ERROR');
}
}).catch(err => {
if (err.description === 'cancelled') console.log('cancelled by user');
console.log(err);
});
Upload Begin
and UploadProgress
's reference are taken form RNFS official documentation. They both act as progress indicators.
let uploadBegin = res => {
var jobId = res.jobId;
console.log('UPLOAD HAS BEGUN! JobId: ' + jobId);
};
let uploadProgress = res => {
var percentage = Math.floor(
(res.totalBytesSent / res.totalBytesExpectedToSend) * 100,
);
console.log('uploading : ' + percentage + '%');
};
Configuring the NodeJs server route with fs.createWriteStream()
My Mistakes :
- I didn't know, how to use
streams
or what they are...
Set up a stream
to receive chunks of the file being uploaded, one at a time, hence, enabling a smooth
router.use('/', Middlewares.authenticateUser)
.post((req, res) => {
let stream = fs.createWriteStream('./output');
req.pipe(stream);
stream.on('drain', ()=>{
// the 'drain' event will be emitted when it is appropriate to resume writing data to the stream.
})
stream.on('close', function () {
console.log("Streaming completed")
res.statusCode(200).json({message: "File has been uploaded"})
});
stream.on('error', function (err) {
console.log(err);
res.statusCode(401).json({message: "File upload has failed."})
});
})
Why use streams ? benefits ?
- Memory efficiency : You don't need to load large amounts of data in memory before you are able to process it.
- Time efficiency : It takes way less time to start processing data as soon as you have it, rather than waiting till the whole data payload is available to start.