How to parse data submitted by FormData() in nodejs? - node.js

I'm submitting base64 image to server side via FormData(). Getting something like
{"------WebKitFormBoundaryjJtrF2zdTOFuHmYM\\r\\nContent-Disposition: form-data; name":"\\"image\\"\\r\\n\\r\\ndata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASoAAABiCAYAAADnRp6aAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQd0FFUXx/9vdtNDSC8kJCEJISEJgd7pz4GGfiqoqm5C1aNSPaqq9hYVVFW1VOXnqaCqoQ1VUKmgqmrXUUFVVUupoKq9pczuoIJKBVVVO5UKqqpaSgVV7S1ldof/A9VZZwflQmSiAAAAAElFTkSuQmCC\\r\\n------WebKitFormBoundaryjJtrF2zdTOFuHmYM--\\r\\n"}
How to parse this to get the image data seperatly.I'm using expressjs as backend.
I'm not submitting a normal image through html form tag. The code :
var src = document.getElementById('hdrimg').src;
var formData = new FormData()
formData.append("image",src);
let response = await fetch('http://localhost:3000/hdrimg', {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: formData
});
Manually submitting source of image with formdata constructor. I tried with multer , express-file-upload as we do for normal files. Is there any other way to retrive the data like this in backend.
{"------WebKitFormBoundaryjJtrF2zdTOFuHmYM\\r\\nContent-Disposition: form-data; name":"\\"image\\"\\r\\n\\r\\ndata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASoAAABiCAYAAADnRp6aAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQd0FFUXx/9vdtNDSC8kJCEJISEJgd7pz4GGfiqoqm5C1aNSPaqq9hYVVFW1VOXnqaCqoQ1VUKmgqmrXUUFVVUupoKq9pczuoIJKBVVVO5UKqqpaSgVV7S1ldof/A9VZZwflQmSiAAAAAElFTkSuQmCC\\r\\n------WebKitFormBoundaryjJtrF2zdTOFuHmYM--\\r\\n"}

You can try like it:
function upload_share_file() {
file = document.getElementById("share_file").files[0]
console.log(file["name"])
startUpload(file, "/srdata?type=file_upload&filename=" + file["name"],
function(response) {
uResponseAlert(JSON.parse(response))
// console.log(response)
file_table()
}
)
}
function startUpload(file, uploadUrl, callback)
{
var request = new XMLHttpRequest();
request.upload.addEventListener("progress", window.evt_upload_progress, false);
request.addEventListener("load", window.evt_upload_complete, false);
request.addEventListener("error", window.evt_upload_failed, false);
request.addEventListener("abort", window.evt_upload_cancel, false);
request.open("POST", uploadUrl);
request.send(file);
request.onreadystatechange = function() {
if (request.readyState === 4) { //run it when get response
console.log(request.response)
callback(request.response);
}
}
}

When using fetch with a FormData as body, do not set the Content-Type header, it will be set automatically to multipart/form-data. Then you can use multer to parse it on the server, as suggested by Marc Stroebel.

Related

Axios : send image with FormData on Prestashop API

I'm trying to upload on image on the Prestashop API with form-data/axios.
For that, i just need to send a post request with the images joined in an "image" parameter.
I did this simple node.js script (mine is much more complicated but i simplified for here):
const FormData = require("form-data");
const fs = require("fs");
const axios = require("axios");
// Read the image file into a buffer
const imageBuffer = fs.readFileSync("image.jpg");
// Create a FormData object
const form = new FormData();
// Append the image buffer to the form data
form.append("image", imageBuffer);
// Make an HTTP POST request to the PrestaShop API
axios({
method: "POST",
url: "https://XXX/api/images/products/15924",
data: form, // set the request body using the data field
params: {
ws_key: "XXX",
},
headers: {
"Content-Type": "multipart/form-data; boundary=" + form.getBoundary(),
},
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error.response.data);
});
But i get this answer:
<message><![CDATA[Please set an "image" parameter with image data for value]]></message>
I tried a LOT of things. With fs.createReadStream instead of formData, with http instead of axios, with a buffer or a file, etc ... and i alway end with this error.
I would be glad if someone has an idea :-)
Thx !
I finally succeed!
Two changed were needed:
Adding the filename in the append (thanks Dmitriy Mozgovoy for pointing that out in the comment)
Adding the size in the headers with "Content-Length": formData.getLengthSync()
Without these 2 missing elements, it seems that PHP received an empty $_FILES variable.
Final version:
const FormData = require("form-data");
const fs = require("fs");
const axios = require("axios");
// Read the image file into a buffer
const imageBuffer = fs.readFileSync("image.jpg");
// Create a FormData object
const form = new FormData();
// Append the image buffer to the form data
form.append("image", imageBuffer, "image.jpg");
// Make an HTTP POST request to the PrestaShop API
axios
.post("https://example.com/api/images/products/15924", form, {
params: {
ws_key: "EXAMPLE",
},
headers: {
...form.getHeaders(),
"Content-Length": form.getLengthSync(),
},
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error.response.data);
});

Grabbing an image from a URL, then passing it to an API as a file in multipart form data

So I have a URL that contains an image, and I want to pass that image as part of multipart form data to an API (to be specific, if it matters, the ClickUp API). I'm doing all of this inside of a Figma plugin, which is a browser environment.
The url looks something like https://s3-alpha-sig.figma.com....
The request works perfectly for a local image that I add manually, such as in Postman. Here is the code for a successful Postman request to this endpoint:
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
data.append('attachment', fs.createReadStream('7UI7S5-pw/fdb54856-9c05-479f-b726-016ef252d9f5.png'));
data.append('filename', 'example.png');
var config = {
method: 'post',
url: 'https://api.clickup.com/api/v2/task/2phh5bf/attachment',
headers: {
'Authorization': '(my auth token)',
...data.getHeaders()
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
However, I don't have access to local files and need to upload from a URL, so here's what I've done so far:
var data = new FormData();
data.append('attachment', open(imgURL));
data.append('filename', 'screenshot.png');
fetch(`(the URL)`, {
"method": "POST",
"muteHttpExceptions": true,
"headers": {
'Authorization': '(my auth token)',
...data.headers
},
data: data
}).then(response => {
console.log(response)
})
How should I be converting the URL into something I can input as Form Data? Thanks so much in advance!

Uploading file via Axios config

I want to change my axios setup to upload multiple files within it
I am trying to pass it to data if the req.file exist
But it does not work
Is there any way to access request file by req.file
What if it is defined in backend?
(Like code below)
axios({
url: URL + req.url,
method: req.method,
...(
(!req.file)
? { data: req.body }
: { data: req.file }
),
})
Add the file to a formData object, and set the Content-Type header to multipart/form-data.
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Reference HERE

Get image from Axios and send as Form Data to Wordpress API in a Cloud Function

What I'm trying to accomplish is using a Firebase Cloud Function (Node.js) to:
First download an image from an url (f.eg. from unsplash.com) using an axios.get() request
Secondly take that image and upload it to a Wordpress site using the Wordpress Rest API
The problem seems (to me) to be that the formData doesnt actually append any data, but the axios.get() request actually does indeed retrieve a buffered image it seems. Maybe its something wrong I'm doing with the Node.js library form-data or maybe I get the image in the wrong encoding? This is my best (but unsuccessfull) attempt:
async function uploadMediaToWordpress() {
var FormData = require("form-data");
var formData = new FormData();
var response = await axios.get(
"https://images.unsplash.com/photo-1610303785445-41db41838e3e?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80"
{ responseType: "arraybuffer" }
);
formData.append("file", response.data);
try {
var uploadedMedia = await axios.post("https://wordpresssite.com/wp-json/wp/v2/media",
formData, {
headers: {
"Content-Disposition": 'form-data; filename="example.jpeg"',
"Content-Type": "image/jpeg",
Authorization: "Bearer <jwt_token>",
},
});
} catch (error) {
console.log(error);
throw new functions.https.HttpsError("failed-precondition", "WP media upload failed");
}
return uploadedMedia.data;
}
I have previously successfully uploaded an image to Wordpress with Javascript in a browser like this:
async function uploadMediaToWordpress() {
let formData = new FormData();
const response = await fetch("https://images.unsplash.com/photo-1610303785445-41db41838e3e?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80");
const blob = await response.blob();
const file = new File([blob], "image.jpeg", { type: blob.type });
formData.append("file", file);
var uploadedMedia = await axios.post("https://wordpresssite.com/wp-json/wp/v2/media",
formData, {
headers: {
"Content-Disposition": 'form-data; filename="example.jpeg"',
"Content-Type": "image/jpeg",
Authorization: "Bearer <jwt_token>",
},
});
return uploadedMedia.data;
},
I have tried the last couple of days to get this to work but cannot for the life of me seem to get it right. Any pointer in the right direction would be greatly appreciated!
The "regular" JavaScript code (used in a browser) works because the image is sent as a file (see the new File in your code), but your Node.js code is not really doing that, e.g. the Content-Type value is wrong which should be multipart/form-data; boundary=----...... Nonetheless, instead of trying (hard) with the arraybuffer response, I suggest you to use stream just as in the axios documentation and form-data documentation.
So in your case, you'd want to:
Set stream as the responseType:
axios.get(
'https://images.unsplash.com/photo-1610303785445-41db41838e3e?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80',
{ responseType: 'stream' }
)
Use formData.getHeaders() in the headers of your file upload request (to the /wp/v2/media endpoint):
axios.post( 'https://wordpresssite.com/wp-json/wp/v2/media', formData, {
headers: {
...formData.getHeaders(),
Authorization: 'Bearer ...'
},
} )
And because the remote image from Unsplash.com does not use a static name (e.g. image-name.jpg), then you'll need to set the name when you call formData.append():
formData.append( 'file', response.data, 'your-custom-image-name.jpeg' );
I hope that helps, which worked fine for me (using the node command for Node.js version 14.15.4, the latest release as of writing).

NodeJS, Axios - post file from local server to another server

I have an API endpoint that lets the client post their csv to our server then post it to someone else server. I have done our server part which save uploaded file to our server, but I can't get the other part done. I keep getting error { message: 'File not found', code: 400 } which may mean the file never reach the server. I'm using axios as an agent, does anyone know how to get this done? Thanks.
// file = uploaded file
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
Update
As axios doc states as below and the API I'm trying to call requires a file
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
// When no transformRequest is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
Is there any way to make axios send a file as a whole? Thanks.
The 2 oldest answers did not work for me. This, however, did the trick:
const FormData = require('form-data'); // npm install --save form-data
const form = new FormData();
form.append('file', fs.createReadStream(file.path));
const request_config = {
headers: {
'Authorization': `Bearer ${access_token}`,
...form.getHeaders()
}
};
return axios.post(url, form, request_config);
form.getHeaders() returns an Object with the content-type as well as the boundary.
For example:
{ "content-type": "multipart/form-data; boundary=-------------------0123456789" }
I'm thinking the createReadStream is your issue because its async. try this.
Since createReadStream extends the event emitter, we can "listen" for when it finishes/ends.
var newFile = fs.createReadStream(file.path);
// personally I'd function out the inner body here and just call
// to the function and pass in the newFile
newFile.on('end', function() {
const form_data = new FormData();
form_data.append("file", newFile, "filename.ext");
const request_config = {
method: "post",
url: url,
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios(request_config);
});
This is what you really need:
const form_data = new FormData();
form_data.append("file", fs.createReadStream(file.path));
const request_config = {
headers: {
"Authorization": "Bearer " + access_token,
"Content-Type": "multipart/form-data"
},
data: form_data
};
return axios
.post(url, form_data, request_config);
In my case, fs.createReadStream(file.path) did not work.
I had to use buffer instead.
const form = new FormData();
form.append('file', fs.readFileSync(filePath), fileName);
const config = {
headers: {
Authorization: `Bearer ${auth.access_token}`,
...form.getHeaders(),
},
};
axios.post(api, form.getBuffer(), config);
I have made an interceptor you can connect to axios to handle this case in node: axios-form-data. Any feedback would be welcome.
npm i axios-form-data
example:
import axiosFormData from 'axios-form-data';
import axios from 'axios';
// connect axiosFormData interceptor to axios
axios.interceptors.request.use(axiosFormData);
// send request with a file in it, it automatically becomes form-data
const response = await axios.request({
method: 'POST',
url: 'http://httpbin.org/post',
data: {
nonfile: 'Non-file value',
// if there is at least one streamable value, the interceptor wraps the data into FormData
file: createReadStream('somefile'),
},
});
// response should show "files" with file content, "form" with other values
// and multipart/form-data with random boundary as request header
console.log(response.data);
I had a same issue, I had a "pdf-creator-service" for generate PDF document from html.
I use mustache template engine for create HTML document - https://www.npmjs.com/package/mustache
Mustache.render function returns html as a string what do I need to do to pass it to the pdf-generator-service ? So lets see my suggestion bellow
//...
async function getPdfDoc(props: {foo: string, bar: string}): Promise<Buffer> {
const temlateFile = readFileSync(joinPath(process.cwd(), 'file.html'))
mustache.render(temlateFile, props)
const readableStream = this.getReadableStreamFromString(htmlString)
const formData = new FormData() // from 'form-data'
formData.append('file', options.file, { filename: options.fileName })
const formHeaders = formData.getHeaders()
return await axios.send<Buffer>(
{
method: 'POST',
url: 'https://pdf-generator-service-url/pdf',
data: formData,
headers: {
...formHeaders,
},
responseType: 'arraybuffer', // ! important
},
)
}
getReadableStreamFromString(str: string): Readable {
const bufferHtmlString = Buffer.from(str)
const readableStream = new Readable() // from 'stream'
readableStream._read = () => null // workaround error
readableStream.push(bufferHtmlString)
readableStream.push(null) // mark end of stream
return readableStream
}
For anyone who wants to upload files from their local filesystem (actually from anywhere with the right streams architecture) with axios and doesn't want to use any external packages (like form-data).
Just create a readable stream and plug it right into axios request function like so:
await axios.put(
url,
fs.createReadStream(path_to_file)
)
Axios accepts data argument of type Stream in node context.
Works fine for me at least in Node v.16.13.1 and with axios v.0.27.2

Resources