How to post a file to a remote url using npm got? - node.js

I'm trying to post a file to a remote URL using npm got. But it is not working as expected.
I have tried the following
const headers = {
"Content-Type": "image/png"
}
const requestProperties = {
method: 'POST',
url,
headers,
json: fs.createReadStream(file.path)
}
const response = await got(requestProperties);
Thank you!

Thank you #phil
I have used body property instead of json.
const headers = {
"Content-Type": "image/png"
}
const requestProperties = {
method: 'POST',
url,
headers,
body: fs.createReadStream(file.path)
}
const response = await got(requestProperties);

Related

UrlFetchApp Google Scripts VS Node Fetch

I'm having some problems to do a simple POST request with UrlFetchApp on Google Scripts.
This code works fine on NodeJS with node-fetch lib.
const fetch = require('node-fetch');
const URL = "https://login.XXXXXXXXXXXXX.com.br/api/login"
fetch(URL, {
"body": "{'my_json_data': 'login data'}",
"method": "POST",
}).then(res => res.text())
.then(body => console.log(JSON.parse(body)));
The same request on a Google Scripts project using UrlFetchApp give me a 403 Forbidden HTTP error.
var url = 'https://login.XXXXXXXXX.com.br/api/login';
var data = {
'email':'EMAIL',
'password':'PASS'
}
var options = {
method: 'POST',
payload: JSON.stringify(data)
}
var response = UrlFetchApp.fetch(url, options);
Logger.log(response)
What am I missing here?
Edit: Already tried with payload.
I believe your goal as follows.
You want to convert the following Node.js script to Google Apps Script.
const fetch = require('node-fetch');
const URL = "https://login.XXXXXXXXXXXXX.com.br/api/login"
fetch(URL, {
"body": "{'my_json_data': 'login data'}",
"method": "POST",
}).then(res => res.text())
.then(body => console.log(JSON.parse(body)));
Modification points:
In your Node.js script, the data of "{'my_json_data': 'login data'}" is sent to data as text/plain. So in this case, when UrlFetchApp is used, the content type is required to be set. Because when the content type is not set, the data is sent as form-data.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
var options = {
method: 'POST',
payload: JSON.stringify(data)
}
To:
var options = {
method: 'POST',
payload: JSON.stringify(data),
contentType: "text/plain"
}
If contentType: "text/plain" occurs an error, please modify it to contentType: "text/plain;charset=UTF-8".
Although I'm not sure about the specification of your API, I thought that contentType: "application/json" might be able to be also used. But this is my guess.
Reference:
Class UrlFetchApp

Making a POST request using puppeteer with JSON payload

I'm trying to make a POST request using puppeteer and send a JSON object in the request, however, I'm getting a timeout... if I'm trying to send a normal encoded form data that at least a get a reply from the server of invalid request...
here is the relevant part of the code
await page.setRequestInterception(true);
const request = {"mac": macAddress, "cmd": "block"};
page.on('request', interceptedRequest => {
var data = {
'method': 'POST',
'postData': request
};
interceptedRequest.continue(data);
});
const response = await page.goto(configuration.commandUrl);
let responseBody = await response.text();
I'm using the same code to make a GET request (without payload) and its working
postData needs to be encoded as form data (in the format key1=value1&key2=value2).
You can create the string on your own or use the build-in module querystring:
const querystring = require('querystring');
// ...
var data = {
'method': 'POST',
'postData': querystring.stringify(request)
};
In case you need to submit JSON data:
'postData': JSON.stringify(request)
If you are sending json, you need to add "content-type": "application/json". If you don't send it you can receive an empty response.
var data = {
method : 'POST',
postData: '{"test":"test_data"}',
headers: { ...interceptedRequest.headers(), "content-type": "application/json"}
};
interceptedRequest.continue(data);

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

Axios: Content-Length header is missing on request headers

we are facing an issue in production that the 'Content-Length' header is not being sent, even if we hard-code it in the headers properties, so we are receiving back from the server the 411 Length Required error.
We are using:
Axios 0.16.2
NodeJS 6.10
Application deployed inside AWS Lambda environment
The code that is causing the issue is the following:
let cookieJar;
const postBody = "MyBody=MyBodyContentGoesHere";
const url = "https://my-url.com";
return axios
.post(url,
postBody,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000,
jar: cookieJar,
withCredentials: true
}
);
I wrote an application in .NET and the header is sent properly (without to pass it manually). This .NET application was written just to test, it's not the real application.
Do you have some idea?
I open a issue in the axios github project, but I want to know from you guys some ideas.
Thank you.
have you tried adding a "data" field to the config object?
let cookieJar;
const postBody = "MyBody=MyBodyContentGoesHere";
const url = "https://my-url.com";
return axios
.post(url,
postBody,
{
data: postBody,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000,
jar: cookieJar,
withCredentials: true
}
);
I'd the same issue as you. Using querystring as suggested in the offical docs solved it for me.
'use strict';
let querystring = require('querystring');
let cookieJar;
const postBody = querystring.stringify({ MyBody: 'MyBodyContentGoesHere' });
const url = 'https://my-url.com';
return axios.post(url, postBody, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000,
jar: cookieJar,
withCredentials: true
}
);

How to send a file in request node-fetch or Node?

How do I attach a file in Node or Node Fetch POST request? I am trying to invoke an API which will import a CSV or XLS file. Is this possible using Node or Node Fetch?
README.md says:
Use native stream for body, on both request and response.
And sources indicate it supports several types, like Stream, Buffer, Blob... and also will try to coerce as String for other types.
Below snippet shows 3 examples, all work, with v1.7.1 or 2.0.0-alpha5 (see also other example further down with FormData):
let fetch = require('node-fetch');
let fs = require('fs');
const stats = fs.statSync("foo.txt");
const fileSizeInBytes = stats.size;
// You can pass any of the 3 objects below as body
let readStream = fs.createReadStream('foo.txt');
//var stringContent = fs.readFileSync('foo.txt', 'utf8');
//var bufferContent = fs.readFileSync('foo.txt');
fetch('http://httpbin.org/post', {
method: 'POST',
headers: {
"Content-length": fileSizeInBytes
},
body: readStream // Here, stringContent or bufferContent would also work
})
.then(function(res) {
return res.json();
}).then(function(json) {
console.log(json);
});
Here is foo.txt:
hello world!
how do you do?
Note: http://httpbin.org/post replies with JSON that contains details on request that was sent.
Result:
{
"args": {},
"data": "hello world!\nhow do you do?\n",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip,deflate",
"Connection": "close",
"Content-Length": "28",
"Host": "httpbin.org",
"User-Agent": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
},
"json": null,
"origin": "86.247.18.156",
"url": "http://httpbin.org/post"
}
If you need to send a file as part of a form with more parameters, you can try:
npm install form-data
pass a FormData object as body (FormData is a kind of Stream, via CombinedStream library)
do not pass header in the options (unlike examples above)
and then this works:
const formData = new FormData();
formData.append('file', fs.createReadStream('foo.txt'));
formData.append('blah', 42);
fetch('http://httpbin.org/post', {
method: 'POST',
body: formData
})
Result (just showing what is sent):
----------------------------802616704485543852140629
Content-Disposition: form-data; name="file"; filename="foo.txt"
Content-Type: text/plain
hello world!
how do you do?
----------------------------802616704485543852140629
Content-Disposition: form-data; name="blah"
42
----------------------------802616704485543852140629--
I was looking for how to use node-fetch to upload files via multipart/form-data and their GitHub docs actually shows how to do this. Below is modified example showing how to attach a buffer to FormData and upload that.
const FormData = require('form-data');
const form = new FormData();
const buffer = // e.g. `fs.readFileSync('./fileLocation');
const fileName = 'test.txt';
form.append('file', buffer, {
contentType: 'text/plain',
name: 'file',
filename: fileName,
});
fetch('https://httpbin.org/post', { method: 'POST', body: form })
.then(res => res.json())
.then(json => console.log(json));
Sharing this for anyone else who googled "node-fetch upload file multipart" like I did.

Resources