I am writing this cloud function in typescript and deploying it to firebase.
This endpoint receives form data http request with some files and then it writes these files to /tmp directory and after that it tries to upload these files to IPFS using pinata api
However, when I call this endpoint, it gives this error: Error uploading files to IPFS: AxiosError: Request failed with status code 400
I am pretty sure that my pinata bearer jwt token is correct
Can anyone pinpoint the problem in my code?
Note: same code is working just fine in a node app (outside firebase cloud function)
Code:
import * as functions from "firebase-functions";
import * as Busboy from "busboy";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as FormData from "form-data";
import axios from "axios";
import * as cors from "cors";
import * as express from "express";
const app = express();
app.use(cors({ origin: true }));
app.use(express.urlencoded({ extended: true }));
const JWT = functions.config().pinata.jwt;
const PINATA_API = functions.config().pinata.api;
app.post("/upload", async (req: any, res: any) => {
if (req.method !== "POST") {
res.status(400).json({ error: "Invalid request method. Please use POST." });
return;
}
const busboy = (Busboy as any)({ headers: req.headers });
req.pipe(busboy);
let tempFileList : any = [];
busboy.on("file", (fieldname: any, file: any, filename: any, encoding: any, mimetype: any) => {
const tempFilePath = path.join(os.tmpdir(), filename.filename);
tempFileList.push(tempFilePath);
const writeStream = fs.createWriteStream(tempFilePath);
file.pipe(writeStream);
writeStream.on("finish", async () => {
console.log("File written to temp folder:", tempFilePath);
});
});
busboy.on("finish", async () => {
try {
for (let tempFilePath of tempFileList) {
let formData = new FormData();
let readStream = fs.createReadStream(tempFilePath);
formData.append("file", readStream);
formData.append(
"pinataOptions",
JSON.stringify({
wrapWithDirectory: true,
})
);
await axios.post(PINATA_API, formData, {
headers: {
...formData.getHeaders(),
"Authorization": `Bearer ${JWT}`
},
});
}
for (const tempFilePath of tempFileList) {
fs.unlink(tempFilePath, (err) => {
if (err) {
console.error("Error deleting temp file:", err);
}
});
}
} catch (error) {
res.status(500).send(`Error uploading files to IPFS: ${error}`);
}
});
busboy.end(req.rawBody);
});
export const uploadNFTs = functions.https.onRequest(app);
I tried to upload files to ipfs using pinata api in my firebase cloud function written in typescript.
I expected the files to be uploaded successfully.
What actually resulted was that error when I call pinata api: AxiosError: Request failed with status code 400
It looks like the problem with the upload code is that
wrapWithDirectory
doesn't really do what you think it might do. It only puts the upload inside of a directory rather than enabling directory uploads. Here is a script you can model after to handle a directory upload. The key is mapping over the files and appending them into an entry.