Uploading Files from React Native to a NodeJs Server using `fs.createWriteStream()`

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.

!! Happy Coding !!

Did you find this article valuable?

Support De-mystify Tech by becoming a sponsor. Any amount is appreciated!