DEV Community

Narongdej Sarnsuwan
Narongdej Sarnsuwan

Posted on • Originally published at narongdej.dev on

Create image upload function in Google Firebase

I want to start a new hobby, where I post the solution to something I can’t find 2-3 google away. If I can’t Google and find my solution in one-shot. I’ll write a short tutorial about it. So here comes the first in this blog.

If you want to create an upload image endpoint inside Google Firebase (Cloud functions), then here is one way you can do it.

import * as functions from 'firebase-functions';
import * as Busboy from 'busboy';
import { tmpdir } from 'os';
import { join } from 'path';
import { createWriteStream, unlinkSync } from 'fs';
import * as FileType from 'file-type';
import * as admin from 'firebase-admin';

admin.initializeApp(); // It will automatically authenticate

export const uploadImage = functions.https.onRequest(async (request, response) => {
  const busboy = new Busboy({
    headers: request.headers,
    limits: {
      fileSize: 2 * 1024 * 1024, // max image size to 1 MB
      files: 1 // Limit to one file upload
    }
  });

  let filepath: string = "";
  const _tmpdir = tmpdir();

  busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
    filepath = join(_tmpdir, filename);
    const writeStream = createWriteStream(filepath);
    file.pipe(writeStream);
  });

  busboy.on('finish', async () => {
    const fileType = await FileType.fromFile(filepath);
    console.log(fileType);
    if(!fileType || !(fileType.mime === "image/jpeg" || fileType.mime === "image/png")) {
      unlinkSync(filepath);
      response.status(500).send({
        'error': 'Invalid file',
        'code': 'invalid_upload_file'
      });
      return;
    }

  await admin.storage().bucket().upload(filepath, {
    // Support for HTTP requests made with `Accept-Encoding: gzip`
    gzip: true,
    metadata: {
      // Enable long-lived HTTP caching headers
      // Use only if the contents of the file will never change
      // (If the contents will change, use cacheControl: 'no-cache')
      cacheControl: 'public, max-age=31536000',
    },
  });

    response.send({
      'status': 'Upload successful'
    });
  busboy.end(request.rawBody);
});
Enter fullscreen mode Exit fullscreen mode

I’m new to Google Firebase and Cloud functions, so this might not be the best way to do it, but it works

So what we did was

  1. Process the form data using busboy
  2. Store the image in a temp directory
  3. Upload the image using firebase-admin storage module

But what about multiple files upload at once?

You can modify this line

    limits: {
      ...
      files: 50 // <--- or remove it to allow infinity
    }
Enter fullscreen mode Exit fullscreen mode

and instead of replacing filepath you create an array of file paths instead. After that, process the filepaths array accordingly in

 busboy.on('finish', async () => {
   ...process the array
 });
Enter fullscreen mode Exit fullscreen mode

Top comments (0)