DEV Community

Cover image for Building a File Upload API with Next.js and Google Drive Integration
Tanvir Ahammed
Tanvir Ahammed

Posted on

Building a File Upload API with Next.js and Google Drive Integration

In this tutorial, we'll walk through the process of creating a serverless API using Next.js that allows users to upload files directly to Google Drive. We'll use the Google Drive API for file storage and Next.js for the serverless API endpoints.

Prerequisites

Before getting started, make sure you have the following:

  1. - A Google Cloud Platform (GCP) project with the Google Drive API enabled.
  2. - API credentials in the form of a service account key (JSON file).
  3. - Node.js and npm installed on your development machine.

Setting Up the Project

  1. Initialize a Next.js Project:
npx create-next-app my-drive-api
cd my-drive-api
Enter fullscreen mode Exit fullscreen mode
  1. Install Dependencies:
npm install googleapis multer stream
Enter fullscreen mode Exit fullscreen mode
  1. Api Code
// pages/api/googleDrive.js
import { google } from "googleapis";
const stream = require("stream");
import multer from "multer";
const apikeys = require("./apikeys.json");
const SCOPE = ["https://www.googleapis.com/auth/drive"];

export const config = {
  api: {
    bodyParser: false,
  },
};

// Function to authorize the Google Drive API
async function authorize() {
  const jwtClient = new google.auth.JWT(
    apikeys.client_email,
    null,
    apikeys.private_key,
    SCOPE
  );

  await jwtClient.authorize();

  return jwtClient;
}

// Multer storage configuration
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

// API endpoint handler
export default async function handler(req: any, res: any) {
  if (req.method !== "POST") {
    return res.status(405).end(); // Method Not Allowed
  }

  try {
    await new Promise<void>((resolve, reject) => {
      upload.single("image")(req as any, res as any, (err) => {
        if (err) {
          return reject(err); // Reject if multer encounters an error
        }
        resolve();
      });
    });

    const uploadedFile = req.file;

    if (!uploadedFile) {
      return res.status(400).json({ error: "No file uploaded" });
    }

    const authClient = await authorize();
    const result: any = await uploadFile(authClient, uploadedFile);

    // Wait for a short delay (e.g., 2 seconds) before responding
    await new Promise((resolve) => setTimeout(resolve, 2000));

    const previewLink = `https://drive.google.com/uc?id=${result?.data?.id}`;

    res.status(200).json({ previewLink, id: result?.data?.id });
  } catch (error: any) {
    console.error(error);
    res.status(500).json({ error: error?.message ?? "Internal Server Error" });
  }
}

// Function to upload a file to Google Drive
async function uploadFile(authClient: any, uploadedFile: any) {
  return new Promise((resolve, reject) => {
    const drive = google.drive({ version: "v3", auth: authClient });

    const fileMetaData = {
      name: uploadedFile.originalname,
      parents: ["1rE3jBXCsPoABRPCyHhvHBqH9SxzzFzCm"],
    };

    drive.files.create(
      {
        resource: fileMetaData,
        media: {
          mimeType: uploadedFile.mimetype,
          body: stream.PassThrough().end(uploadedFile.buffer),
        },
        fields: "id",
      },
      (error: any, file: any) => {
        if (error) {
          return reject(error); // Reject if there's an error during file creation
        }

        // Set permissions to make the file public
        drive.permissions.create(
          {
            fileId: file.data.id,
            requestBody: {
              role: "reader",
              type: "anyone",
            },
          },
          (err: any) => {
            if (err) {
              console.error(err);
              return reject(err); // Reject if there's an error setting permissions
            }
            resolve(file);
          }
        );
      }
    );
  });
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)