node-formidable / formidable

The most used, flexible, fast and streaming parser for multipart form data. Supports uploading to serverless environments, AWS S3, Azure, GCP or the filesystem. Used in production.
MIT License
7.01k stars 680 forks source link

issue when trying to send data with formidable & form-data #790

Closed ElSeniorMikael closed 2 years ago

ElSeniorMikael commented 2 years ago

package : FORMIDABLE v 2.0.1 FormData v 4.0.0

Hello everyone here is my problem, i'm sending file from a form with Next.js ... i'm getting the data from the client and send it to my API so my API can send it to an external. i receive my data in my API which i have no problem there, i also could send directly to my external API and it would receive my data without problem but since we want to use the Next api so we can hide our secret code we want to use the next api where it give me problem.

i've been search in multiple forums and we couldn't find any solution that could work. so i will be explaining our step and then i will output the whole code together at the end

so in our api we receive our req & res that we pass right away with FORMIDABLE v 2.0.1 => ` const parsedData: { fields?: {}; files?: {} } = await new Promise(function ( resolve, reject ) { const form = new formidable.IncomingForm({ keepExtensions: true });

form.parse(req, function (err, fields, files) {
  console.log("parsing");
  if (err) {
    console.log("err", err);

    return reject(err);
  }
  resolve({ fields, files });
});

}); `

after being parsed we pass the parsed data in your function to recontruct our data by doing so =>

` const reconstructedData = await reconstructData(await parsedData)

function reconstructData(parsedData:any) {

let newData = new FormData();

Object.entries(parsedData.fields).forEach(element => { newData.append(element[0], element[1][0]) });

Object.entries(parsedData.files).forEach((element:any) => { newData.append(element[0], element[1], element[1].originalFilename) })

return newData } `

then we continue with sending our data to the external API =>

const response = await fetch(url, { method: "POST", headers: myHeaders, body: reconstructedData as FD, });

We get an Node error that say => error - TypeError: source.pause is not a function

So we are kind of stuck at this point

FULL SOURCE API CODE

` import { NextApiRequest, NextApiResponse } from "next"; import formidable from 'formidable'; import FormData from 'form-data'; import {FormData as FD} from 'node-fetch'

import ContactFormType from "@/interfaces/Forms/FormType";

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

export default async function handler( req: NextApiRequest, res: NextApiResponse ) { console.log("req body", req.body);

const parsedData: { fields?: {}; files?: {} } = await new Promise(function ( resolve, reject ) { const form = new formidable.IncomingForm({ keepExtensions: true });

form.parse(req, function (err, fields, files) {
  console.log("parsing");
  if (err) {
    console.log("err", err);

    return reject(err);
  }
  resolve({ fields, files });
});

});

console.log('parsed data ', parsedData)

try { const reconstructedData = await reconstructData(await parsedData)

let authString = `${process.env.GRAVITY_FORM_CONSUMER}:${process.env.GRAVITY_FORM_SECRET}`;

const url = `${process.env.FORMS_URL}/2/submissions`;

const myHeaders = new Headers({
  Authorization: "Basic " + Buffer.from(authString).toString("base64"),
});

const response = await fetch(url, {
  method: "POST",
  headers: myHeaders,
  body: reconstructedData as FD,
});

if (response.status === 400) {
  console.log("res: ", response, req.body);

  return res.status(500).json({
    code: 400,
    message: `Il y a eu une erreur lors de l\'envoi du formulaire.`,
  });
}

const data = await response.json();

return res
  .status(200)
  .json({ code: 200, message: data.confirmation_message });
 } catch (error) {
   console.log("error");
   return res.status(500).json({
     message: `Il y a eu une erreur lors de l\'envoi du formulaire.`,
   });
 }

}

function reconstructData(parsedData:any) {

let newData = new FormData();

Object.entries(parsedData.fields).forEach(element => {

newData.append(element[0], element[1][0])

});

Object.entries(parsedData.files).forEach((element:any) => { console.log('elem file ', element[1].filePath, element[1].originalFilename, typeof element[1], element[1])

newData.append(element[0], element[1], element[1].originalFilename)

})

return newData } `

GrosSacASac commented 2 years ago

Who is going to read that ?

ElSeniorMikael commented 2 years ago

problem solved

we ended up doing a fs.createReadSteam in our function =>

` function reconstructData(parsedData:any) { let newData = new FormData();

Object.entries(parsedData.fields).forEach(element => { newData.append(element[0], element[1]) });

Object.entries(parsedData.files).forEach((element:any) => { newData.append(element[0], fs.createReadStream(element[1].filepath), element[1].originalFilename) })

return newData } `

similar problem => #359