DEV Community

Faith Morante
Faith Morante

Posted on • Edited on

File upload with React, Express and Google Cloud Storage with folder structure

For the front end, we will use FilePond. It has a plugin for React for file uploads that supports previews, validations, drag and drop, etc.
NOTE: This tutorial assumes that you know how to setup React and Express.

Start by yarn/npm installing these:

react-filepond
filepond
filepond-plugin-image-preview
filepond-plugin-image-exif-orientation

import { FilePond, registerPlugin } from "react-filepond"
import "filepond/dist/filepond.min.css"
import FilePondPluginImageExifOrientation from "filepond-plugin-image-exif-orientation"
import FilePondPluginImagePreview from "filepond-plugin-image-preview"
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css"
Enter fullscreen mode Exit fullscreen mode

Filepond component looks like this

<FilePond 
  files={imgCollection}
  allowMultiple={true}
  server={null}
  instantUpload={false}
  onupdatefiles={(fileItems) => onFileChange(fileItems)}>
</FilePond>
Enter fullscreen mode Exit fullscreen mode

I use a form submit to trigger uploading of file/s.

Form:

<form onSubmit={onSubmit}>
    <div className="form-group">
        <button className="btn btn-primary" type="submit">Upload</button>
    </div>
    <div className="filepond-wrapper">
        <FilePond 
            files={imgCollection}
            allowMultiple={true}
            server={null}
            instantUpload={false}
            onupdatefiles={(fileItems) => onFileChange(fileItems)}>
        </FilePond>
    </div>
</form>
Enter fullscreen mode Exit fullscreen mode

Functions and states:

    const [imgCollection, setImgCollection] = useState('')

    const onFileChange = (files) => {
        let items = files.map(fileItem => fileItem.file)
        setImgCollection([...imgCollection, items])
    }

    const onSubmit = (e) => {
        e.preventDefault()

        var formData = new FormData()

        for (let img in imgCollection[0]) {
            formData.append('imgCollection', imgCollection[0][img])
        }

        formData.append('folder', 'folder-name')

        axios.post(`${process.env.REACT_APP_API_ENDPOINT}/`, formData, {
        }).then(res => {
            console.log(res.data)
        })
    }
Enter fullscreen mode Exit fullscreen mode

Install multer in your api folder.
In your Express API:

var express = require('express');
var router = express.Router();
var path = require('path')
var multer  = require('multer')
var upload = multer().array('imgCollection')

router.post('/', function(req, res, next) {
  // Imports the Google Cloud client library.
  const {Storage} = require('@google-cloud/storage');

  const storage = new Storage({projectId: 'gcp-project-id', keyFilename: path.join(__dirname, '../creds.json')});

  try {
    async function uploadFile(file, folder) {
      let bucketName = 'bucket-name'
      let bucket = storage.bucket(bucketName)

      let newFileName = folder + '/' + file.originalname;

      let fileUpload = bucket.file(newFileName);
      const blobStream = fileUpload.createWriteStream({
          metadata: {
              contentType: file.mimetype
          }
      });

      blobStream.on('error', (error) => {
          console.log('Something is wrong! Unable to upload at the moment.' + error);
      });

      blobStream.on('finish', () => {
          const url = `https://storage.googleapis.com/${bucket.name}/${fileUpload.name}`; //image url from firebase server
          console.log(url)

      });

      blobStream.end(file.buffer);
    }

    upload(req, res, function(err) {
      let files = req.files

      for (let file in files) {
        uploadFile(files[file], req.body.folder)
      }

      if(err) {
          return res.end("Error uploading file." + err);
      }
      res.end("File is uploaded");
    })
  } catch (err) {
    res.send(err)
  }
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

And that's it!

Hope you liked it.

Rock on,
FM

Top comments (13)

Collapse
 
vijajsoninoetic profile image
vijaj-soni-Noetic

const [imgCollection, setImgCollection] = useState('')
const [client, setClient] = useState('')
const [section, setSection] = useState('Section')

const onFileChange = (files) => {
    let items = files.map(fileItem => fileItem.file)
    setImgCollection([...imgCollection, items])
}

where i use these line of code its given me error

Collapse
 
idiglove profile image
Faith Morante

Hello,

What error do you get? Note, I'm using React Hooks.

Collapse
 
rterrell25 profile image
Robert Terrell

I noticed when i submit a file using the form it uploads correctly but for some reason it turns red and states error during load. My console shows the following: filepond.js:3139 GET localhost:3000/%5Bobject%20Object%5D 404 (Not Found) is there something I need to do to prevent this?

Collapse
 
idiglove profile image
Faith Morante

I wont be able to see that link as it is served through your localhost. Can you provide a screenshot of the error? thanks

Collapse
 
rterrell25 profile image
Robert Terrell • Edited

That's what the error displays as in the console. The error message is the following:

"filepond.js:3139 GET localhost:3000/%5Bobject%20Object%5D 404 (Not Found)"

the file input turns red and continually flickers saying error during load. What's strange tho is that the file uploads correctly and displays, so im wondering if its the file change code that's possibly creating the error.

Collapse
 
anuradha677 profile image
Anuradha677

Hi
I am using express-fileuploader for uploading the files. Cloud you please tell me how to use that to upload the image to storage?

Thanks in advance.

Collapse
 
idiglove profile image
Faith Morante

Please refer to their documentation. I haven't used that, sorry

Collapse
 
rterrell25 profile image
Robert Terrell

You've never once called your onSubmit function, where exactly are you using it

Collapse
 
idiglove profile image
Faith Morante

Sorry about that, the onSubmit was on my form tag. Will update my post now :)

Collapse
 
rterrell25 profile image
Robert Terrell

thanks

Collapse
 
sboudouk profile image
Sami

So you're basically uploading 2 times: On your servers, then on Google Cloud Platform ?

Collapse
 
idiglove profile image
Faith Morante

on GCP only

Collapse
 
dikshit1805 profile image
dikshit n

How do we handle upload files greater than 30MB ??