Upload files to Google Drive With React+NodeJS

With the help of NodeJS and Multer

Today we will learn how we can upload files to google drive using service account. It will allow us to avoid implementing OAuth2 authentication.

Pre-requisites

  1. The first order of business is to create a service account and get the key.json file. from your google cloud console
  2. Then you will need to enable google drive API on your console
  3. In the downloaded key.json file you will see a client_email field. Copy that value.
  4. Go to the google drive that you want to access via API and share that folder/files with that email account.

The final step is important because it will allow us to avoid implementing OAuth2 authentication.

Prepare the front-end

Create a new ReactJS application and

The front-end code is very easy. We will just need a file picker to select a file from our local machine and send it to our nodejs server.

import React, { useState } from "react";

function GoogleDriveFileUploader() {
  const [url, setUrl] = useState("");
  const [file, setFile] = useState < any > null;
  const handleSubmit = async (e: any) => {
    e.preventDefault();
    let formData = new FormData();
    formData.append("file", file.data);
    const response = await fetch("http://localhost:5001/upload-to-google-drive", {
      method: "POST",
      body: formData,
    });

    const responseWithBody = await response.json();
    if (response) setUrl(responseWithBody.publicUrl);
  };

  const handleFileChange = (e: any) => {
    const file = {
      preview: URL.createObjectURL(e.target.files[0]),
      data: e.target.files[0],
    };
    setFile(file);
  };
  return (
    <form onSubmit={handleSubmit}>
      <input type="file" name="file" onChange={handleFileChange}></input>
      <button type="submit">Submit</button>
    </form>
  );
}

export default GoogleDriveFileUploader;

This is a simple component that will allow us to choose a file from the local storage and call our api that we are going to develop next.

Prepare the backend

Let's first initialize the project by installing some dependencies.

yarn add googleapis express cors multer

here multer is a special middleware for express that helps with file uploads

googleapis is our way to interact with google cloud API's.

Let's first review what we are going to do.

Configure multer

  1. We will configure our disk storage using multer. This will allow us to store the incoming file into a specified folder.
import Multer from "multer";

const multer = Multer({
  storage: Multer.diskStorage({
    destination: function (req, file, callback) {
      callback(null, `${__dirname}/audio-files`);
    },
    filename: function (req, file, callback) {
      callback(null, file.fieldname + "_" + Date.now() + "_" + file.originalname);
    },
  }),
  limits: {
    fileSize: 5 * 1024 * 1024,
  },
});

Authenticate our application

Then we will create authorize our application code using the key.json file.

import { google } from "googleapis";

const authenticateGoogle = () => {
  const auth = new google.auth.GoogleAuth({
    keyFile: `${__dirname}/service-account-key-file.json`,
    scopes: "https://www.googleapis.com/auth/drive",
  });
  return auth;
};

Then create our function to handle the file upload feature.

const uploadToGoogleDrive = async (file: any, auth: any) => {
  const fileMetadata = {
    name: file.originalname,
    parents: ["1T8smHRI3g1Or9pSjxsV_BDFvR4LepqZu"], // Change it according to your desired parent folder id
  };

  const media = {
    mimeType: file.mimetype,
    body: fs.createReadStream(file.path),
  };

  const driveService = google.drive({ version: "v3", auth });

  const response = await driveService.files.create({
    requestBody: fileMetadata,
    media: media,
    fields: "id",
  });
  return response;
};

Notice there is a parents array in the fileMetadata field. This is the id of the google drive folder that we want to upload the file to.

And after we upload the file to google drive we want to delete the file as well. Let's create another function for that.

const deleteFile = (filePath) => {
  fs.unlink(filePath, () => {
    console.log("file deleted");
  });
};

And finally let's get our endpoint and use all of these together.

app.post("/upload-file-to-google-drive", multer.single("file"), async (req: any, res: any, next: any) => {
  try {
    if (!req.file) {
      res.status(400).send("No file uploaded.");
      return;
    }
    const auth = authenticateGoogle();
    const response = await uploadToGoogleDrive(req.file, auth);
    deleteFile(req.file.path);
    res.status(200).json({ response });
  } catch (err) {
    console.log(err);
});

Get the list of the files

In a previous step we noticed that we used an ID to specify the folder that we want to upload the file to. We can use the following function to list the available files and folders that are shared with this particular service account.

const response = await drive.files.list(params);

And from the response we will get a list where the file id can be found.

Uploading file without storing it

The above solution works perfectly. Until get the requirement that you can't store the file on the disk.

For example when you are running the application inside docker without the root privilege then you have to grant the permission to that non-root user. otherwise you will get error because that particular user can't store the file into the storage.

To get around this issue we have another option that Multer provides us. We can just use multer's memorystorage.

it will store the files in the application memory. Shouldn't be a problem if the file sizes are not super crazy. Just configure that here.

import Multer from "multer";

const multer = Multer({
  storage: Multer.memoryStorage(), // change this into memoryStorage from diskStorage
  limits: {
    fileSize: 5 * 1024 * 1024,
  },
});

And you are good to go!

That's it for today. Hope you learned something new today.


Share this post


Profile Image

Who I am

Hi, I amMohammad Faisal, A full-stack software engineer @Cruise , working remotely from a small but beautiful country named Bangladesh.

I am most experienced inReactJS,NodeJS andAWS

Buy Me a Coffee Widget