I am trying to use an API to update a list on another server using node.js. For my last step, I need to send a POST that contains a csv file. In the API, they list under FormData that I need a Key called file and a Value of Binary Upload, then the body of the request should be made of listname: name and file: FileUpload.
function addList(token, path, callback) {
//Define FormData and fs
var FormData = require('form-data');
var fs = require('fs');
//Define request headers.
headers = {
'X-Gatekeeper-SessionToken': token,
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
};
//Build request.
options = {
method: 'POST',
uri: '{URL given by API}',
json: true,
headers: headers
};
//Make http request.
req(
options,
function (error, response, body) {
//Error handling.
if (error) { callback(new Error('Something bad happened')); }
json = JSON.parse(JSON.stringify(response));
callback.call(json);
}
);
//Attempt to create form and send through request
var form = new FormData();
form.append('listname', 'TEST LIST');
form.append('file', fs.createReadStream(path, { encoding: 'binary' }));
form.pipe(req);};
I am a veteran of front end javascript for html and css, but this is my first adventure with backend node.js. The error I keep getting is: TypeError: dest.on is not a function
From what I can tell, this has to do with the way I used form.pipe(req) but I can't find documentation telling me the appropriate usage. If you don't have a direct answer, a finger pointing toward the right documentation would be appreciated.
The issue is you're not passing the request instance into your pipe call, you're passing the request module itself. Take a reference to the return value of your req(...) call and pass this instead i.e.
//Make http request.
const reqInst = req(
options,
function (error, response, body) {
//Error handling.
if (error) { callback(new Error('Something bad happened')); }
json = JSON.parse(JSON.stringify(response));
callback.call(json);
}
);
//Attempt to create form and send through request
var form = new FormData();
...
form.pipe(reqInst);
This line:
.pipe(fileinclude)
Should be this:
.pipe(fileinclude())
from
why am i getting this error? dest.on is not a function - using gulp-file-include
Related
I have a data object containing strings, booleans, arrays, objects and even Blobs like this:
Now I want to send this object to my Node.js server...
Using traditional fetch API or Ajax I'm unable to send the blobs and they appear like an empty object server side!
I tried to use fetch API even using FormData approach like:
Client:
const fd = new FormData();
fd.append("upload", data); // data is the object to send
fetch('/mother/new-card', {
method: 'post',
body: fd,
})
Server:
controller side:
router.post('/new-card', newCard);
function newCard(req, res) {
motherService.newCard(req)
.then(result => res.json(result))
.catch(err => {
console.log(err);
res.json(err)
});
}
Service side:
async function newCard(req) {
console.log('req.body', req.body);
return { success: req.body }
}
I usually get undefined trying above methods ...
Is there any valid way to send an object with blobs in it?
I have problem uploading file using POST request in Node.js. I have to use request module to accomplish that (no external npms). Server needs it to be multipart request with the file field containing file's data. What seems to be easy it's pretty hard to do in Node.js without using any external module.
I've tried using this example but without success:
request.post({
uri: url,
method: 'POST',
multipart: [{
body: '<FILE_DATA>'
}]
}, function (err, resp, body) {
if (err) {
console.log('Error!');
} else {
console.log('URL: ' + body);
}
});
Looks like you're already using request module.
in this case all you need to post multipart/form-data is to use its form feature:
var req = request.post(url, function (err, resp, body) {
if (err) {
console.log('Error!');
} else {
console.log('URL: ' + body);
}
});
var form = req.form();
form.append('file', '<FILE_DATA>', {
filename: 'myfile.txt',
contentType: 'text/plain'
});
but if you want to post some existing file from your file system, then you may simply pass it as a readable stream:
form.append('file', fs.createReadStream(filepath));
request will extract all related metadata by itself.
For more information on posting multipart/form-data see node-form-data module, which is internally used by request.
An undocumented feature of the formData field that request implements is the ability to pass options to the form-data module it uses:
request({
url: 'http://example.com',
method: 'POST',
formData: {
'regularField': 'someValue',
'regularFile': someFileStream,
'customBufferFile': {
value: fileBufferData,
options: {
filename: 'myfile.bin'
}
}
}
}, handleResponse);
This is useful if you need to avoid calling requestObj.form() but need to upload a buffer as a file. The form-data module also accepts contentType (the MIME type) and knownLength options.
This change was added in October 2014 (so 2 months after this question was asked), so it should be safe to use now (in 2017+). This equates to version v2.46.0 or above of request.
Leonid Beschastny's answer works but I also had to convert ArrayBuffer to Buffer that is used in the Node's request module. After uploading file to the server I had it in the same format that comes from the HTML5 FileAPI (I'm using Meteor). Full code below - maybe it will be helpful for others.
function toBuffer(ab) {
var buffer = new Buffer(ab.byteLength);
var view = new Uint8Array(ab);
for (var i = 0; i < buffer.length; ++i) {
buffer[i] = view[i];
}
return buffer;
}
var req = request.post(url, function (err, resp, body) {
if (err) {
console.log('Error!');
} else {
console.log('URL: ' + body);
}
});
var form = req.form();
form.append('file', toBuffer(file.data), {
filename: file.name,
contentType: file.type
});
You can also use the "custom options" support from the request library. This format allows you to create a multi-part form upload, but with a combined entry for both the file and extra form information, like filename or content-type. I have found that some libraries expect to receive file uploads using this format, specifically libraries like multer.
This approach is officially documented in the forms section of the request docs - https://github.com/request/request#forms
//toUpload is the name of the input file: <input type="file" name="toUpload">
let fileToUpload = req.file;
let formData = {
toUpload: {
value: fs.createReadStream(path.join(__dirname, '..', '..','upload', fileToUpload.filename)),
options: {
filename: fileToUpload.originalname,
contentType: fileToUpload.mimeType
}
}
};
let options = {
url: url,
method: 'POST',
formData: formData
}
request(options, function (err, resp, body) {
if (err)
cb(err);
if (!err && resp.statusCode == 200) {
cb(null, body);
}
});
I did it like this:
// Open file as a readable stream
const fileStream = fs.createReadStream('./my-file.ext');
const form = new FormData();
// Pass file stream directly to form
form.append('my file', fileStream, 'my-file.ext');
const remoteReq = request({
method: 'POST',
uri: 'http://host.com/api/upload',
headers: {
'Authorization': 'Bearer ' + req.query.token,
'Content-Type': req.headers['content-type'] || 'multipart/form-data;'
}
})
req.pipe(remoteReq);
remoteReq.pipe(res);
I am programatically setting a FormData like so:
const formData = new FormData();
formData.append('id', '12345678');
After which I am sending a POST request with this object. (using angular HttpClient).
I am using Postman to debug the request and see what values were sent by importing the request as cURL and I see that the formData values appear differently.
key:------WebKitFormBoundaryI1mdsdmKkradYVMS\r\nContent-Disposition: form-data; name
value: "id"\r\n\r\n12345678\r\n------WebKitFormBoundaryI1mdsdmKkradYVMS--\r\n
What am I doing wrong?
I want to the send the data so that the server will receive an x-form-urlencoded request with the following object:
key: id
value: 12345678
EDIT: The solution is this:
const body = new URLSearchParams({id: "12345678"});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
})
};
return this.http.post(url, body.toString(), httpOptions).pipe(mergeMap( (response:any) => {
console.log('response ', response);
return of (response);
}));
Thanks,
Yaron
FormData objects generate multipart/form-data, not application/x-www-form-urlencoded by default.
They are designed for handling file uploads for which there are no standard encoding method in application/x-www-form-urlencoded.
Use a URLSearchParams object if you want to generate application/x-www-form-urlencoded data.
const formData = new FormData();
formData.append('id', '12345678');
const query = new URLSearchParams(formData);
console.log(query.toString());
#Quentin's answer is all good, but not that suited to Angular.
Simply pass a second parameter to your GET call :
return this.http.get<any>('url', { params: { id: '123456789' }});
You don't need to make post requests to add url parameters, and you don't need post requests if you don't provide a body.
I am trying to access a php script on a server that returns a JSON object. I am trying to do this with pure JS (not jQuery or React).
I have the following JS:
//Define Parameters:
var param1 = document.getElementById("param1");
var param2 = document.getElementById("param2");
//Send data to the server:
function sendData() {
var XHR = new XMLHttpRequest();
//On Success:
XHR.addEventListener("load", function(event) {
alert(event.target.responseText);
});
//On Fail:
XHR.addEventListener("error", function(event) {
alert('Oops! Something went wrong.');
});
//Setup the request:
XHR.open("POST", "https://www.example.com/folder/file.php");
XHR.setRequestHeader('Content-Type', 'application/json');
//Perform the request:
XHR.send(JSON.stringify({
param1: param1,
param2: param2
}));
}
These parameters are inputted from a HTML page by the user. It seams that the request is not sending to POST parameters and the request type is OPTIONS not POST.
EDIT 1:
As suggested in the comments, I have tried a fetch request and the request is working. It does not appear to be passing my POST parameters through. My code is as follows.
//Define Parameters:
var param1 = document.getElementById("param1");
var param2 = document.getElementById("param2");
var formData = new FormData(document.getElementById('form'));
formData.append('param1', param1);
formData.append('param2', param2);
//Send data to the server:
function sendData() {
var url = 'https://www.example.com/folder/file.php';
fetch(url, {
method: 'POST',
body: formData,
headers:{
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
}
}).then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));
}
Remove the headers section in your fetch request so that the defaults are used instead.
Have you checked to see that the right type of data is being sent in the fetch request? The wrong type being received in a field can mess with the results you see. What errors are you receiving?
This link may also describe something you're running into on the fetch:
https://stanko.github.io/uploading-files-using-fetch-multipart-form-data/
(This really should be a comment, but I don't have the reputation for that, sorry).
I'm trying to get image url, and then post it somehow(either with FormData)...
I've found some usefull info here
1, 2, 3 ...
I've tried several variants of code. but still cant' load image to server.
My code now :
var FormData = require('form-data');
var request = require('request');
var form = new FormData();
request.get(url, {encoding:null}, function (error, response, body) {
form.append('my_logo', body);
form.getLength(function(err,length){
console.log(length);
var r = request.post(upload_url, { headers: { 'content-length': length } }, function(err, httpResponse, body) {
if (err) console.log(+err)
var res = (typeof body == 'string') ? JSON.parse(body) : body;
console.log(res);
})
r._form = form
});
})
in response from Post request i receive information, that loaded undefined...
I use request and form-data library...
How could i do that right?
Maybe with native node.js code it will be better?