0

I'm trying to upload a file to the OpenAI API using Firebase Cloud Functions, Express and Multer. I have a React UI that I'm using to upload a file to my back end to then send to the OpenAI API, but I'm stuck on an issue with Multer. Whenever I try to upload a file through my React UI Multer either doesn't receive it or errors:

Error: unexpected end of form

I want to be able to see the file and any other request parameters that I send to the endpoint in the console debug statements. My back end code:

import {onRequest} from "firebase-functions/v2/https";
import express from "express";
import cors from "cors";
import multer from "multer";

const app = express();
app.use(cors({origin: true}));
app.use(express.json());
app.use(express.urlencoded({extended: true}));

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

// Healthcheck endpoint
app.get("/healthcheck", (req, res) => {
  res.status(200).json({
    status: "ok",
    timestamp: new Date().toISOString(),
    message: "Backend is running",
  });
});

// Parse file endpoint
app.post("/parse-file", upload.single("uploadFile"), async (req, res) => {
  console.log("Content-Type:", req.headers);
  console.log("File received:", req.file); // Currently only seeing undefined
  console.log("Body:", req.body); // Currently only seeing {} but I want to see any params I pass to it such as { uid: "123456" }
  res.json({ok: true, body: req.body});
  return;
});

export const api = onRequest(app);

UI code:

import axios from "axios"
import React, { useState } from "react"

const UploadDocument: React.FC = () => {
  const [file, setFile] = useState<File | undefined>(undefined)
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!file) return;

    const formData = new FormData();
    formData.append("uploadFile", file);
    formData.append("uid", user?.uid || "test"); // Replace with real UID later

    axios
      .post("MY_BACKEND_URL/api/parse-file", formData)
      .then((response) => {
        console.log("Backend response:", response.data);
      })
  }
  return (
    <form onSubmit={handleSubmit}>
      <input type="file" name="uploadFile" onChange={(e) => setFile(e.target.files?.[0])} />
      <button type="submit">Send to OpenAI</button>
    </form>
  )
}

If I use the most recent stable version of Multer I see:

Error: unexpected end of form.

If I use Multer v1.4.2 or v1.4.3 the API returns {ok: true, body: {}} saying the file was undefined. Other fields I pass to the endpoint do not show up either (like the uid field in the UI or a test field, the body is empty).

In my back end I've tried moving app.use(express.json()) after and before creation of the endpoint. Using Busboy directly instead of Multer returns:

Error: unexpected end of form

upload.single("uploadFile") matches. Different versions of Firebase functions didn't change the result. Hitting the endpoint manually through Postman instead of my UI got the same results. I'm assuming it's not a CORS issue. In my UI adding headers manually for multipart/form-data received the same result. Adding the file name to formData like formData.append("uploadFile", file, file.name) received the same result.

How can I upload a file to the OpenAI API?

3
  • 1
    Please edit the question to show all relevant code, including the web client. We should be able to take your code and run it for ourselves to observe the same result. Please also be clear about what is the result you're expecting, and what happens that's different than what you expect. Commented Oct 8 at 22:18
  • I thought this sounded familiar. Here's an answer from @DougStevenson that might help ~ How to perform an HTTP file upload using express on Cloud Functions for Firebase (multer, busboy) Commented Oct 9 at 4:42
  • Awesome thank you I can take a look at that. I ended up getting it to work by simply uploading the file as binary data and passing custom headers for a user ID and the document ID. Is there something inherently wrong or insecure about this approach? Commented Oct 10 at 14:22

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.