Post form with file using Node.js - node.js

There is an external (I can't change it) API for creating articles. Using this API I succeed create an article this way:
curl -F "article[id]=607822" -F "article[file]=#/article_file_example/article" 'https://api/v2/articles'
How can I perform this following http request using Node.js (preferably with axios)?
The code should work for both Linux and Windows, so I can't use require('child_process').exec
I tried the following:
const formData = {
'id': 607822,
file: fs.createReadStream(filePath), //filePath is the absolute path to the file
};
axios.post('https://api/v2/articles', {article: formData});
But the API response is validation error, which means I didn't succeed to imitate the curl command.
Any suggestions?
P.S. There is also an impovement I would like to perform once I have a working solution. I have the file content, so I prefer to send it directly without creating the file + createReadStream. I tried to do that Blobing the context, but didn't succeed.

Looks like axios doesn't support sending multipart/form-data: https://github.com/mzabriskie/axios/issues/789
My solution was based on one of the answers for:
Nodejs POST request multipart/form-data
I used restler module.
I couldn't send my data just as:
{
article: {
'id': 607822,
file: restler.file(filePath, null, stats.size, null, "text/plain")
}
}
since it wasn't retrieved correctly by server.
So I had to transform it to:
{
'article[id]': 607822,
'article[file]': restler.file(filePath, null, stats.size, null, "text/plain")
}

Related

Does the vimeo nodejs API support uploading using the 'pull' approach

I'm trying to use the pull approach for vimeo api uploading, but the vimeo UI shows the films 'uploading' forever, and none of the metadata I've included in the post request makes it to vimeo either.
My request looke like this (i've redacted some of it). The signedURL works and has an expiry of 1 day.
{
path: '/users/xxxxx/videos',
query: {
upload: {
approach: 'pull',
size: 27759876,
link: 'https://storage.googleapis.com/xxxxxx/xxxxxxx%2F0079e513eb90623236b9fce0ebdc5a29%2Ffilm%2F0079e513eb90623236b9fce0ebdc5a29.m4v?GoogleAccessId=xxxxxxxxxxxxxxxxxxxx&Expires=1599054191&Signature=jLEDJ8iNaRC4eDn37DHoCilhKMmDk04h17Vu%2FbDUJbNFxdbjR9CowMQWdn95MdrX....etc'
},
name: 'xxxx',
description: 'xxxxxxx',
privacy: {
download: true,
embed: 'private',
comments: 'nobody',
view: 'anybody'
}
},
method: 'post'
}
and the response back from vimeo appears valid - with lots of vimeo metadata and a vimeo id for the uploaded film.
Looking at the nodejs api on github I only see tus upload approach examples - so now I'm wondering if the client actually supports the pull approach. Has anyone been able to get it to work?
You'll want to use the params property instead of query; using params will put your metadata into the request body instead of providing it as a query parameter.
params is mentioned in the docs as part of the upload method, but it should be used with the request method when making a POST or PATCH.
I think your example request is fine, just swap params for query
https://github.com/vimeo/vimeo.js#uploading-videos
https://github.com/vimeo/vimeo.js/blob/c7a1a16c1805539a00bc37d661b81c10e2108a75/example/upload.js#L63

Invalid credentials problem when consumig tone analizer from a nodejs app

I'm trying to consume a tone analyzer service from a nodejs app. I get unauthorized access problem, but these credentials work fine when I use them in a curl.
Running locally, in my app.js file I've included the data of the tone analyzer as follows:
var ToneAnalyzerV3 = require('watson-developer-cloud/tone-analyzer/v3');
var toneAnalyzer = new ToneAnalyzerV3({
version: '2017-09-21',
iam_apikey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
});
Then I've added this, so my app listens for post requestes in the /tone url:
app.post('/tone', function(req, res, next) {
var params = {'tone_input': req.body}
toneAnalyzer.tone(params, function(err, data) {
if (err) {
return next(err);
}
return res.json(data);
});
});
But when I call it I get "Unauthorized: Access is denied due to invalid credentials".
The thing is that these credentials work fine in curl:
curl -X POST -u "apikey:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX" --header "Content-Type: application/json" --data-binary #tone.json "https://gateway-lon.watsonplatform.net/tone-analyzer/api/v3/tone?version=2017-09-21&sentences=false"
{"document_tone":{"tones":[{"score":0.6165,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.829888,"tone_id":"analytical","tone_name":"Analytical"}]}}
The reason you are getting unauthorised errors when running locally is that your service is hosted in https://gateway-lon.watsonplatform.net. If you don't specify an endpoint / url in your ToneAnalyzerV3 constructor then the API / SDK defaults to Dallas. So although your credentials may be correct for London, they are not correct for Dallas.
When you deployed your app to the cloud (which I guess was to the London location), you probably bound the service into your application. This sets environment variables allowing the SDK to determine the endpoint.
You constructor should look like:
var toneAnalyzer = new ToneAnalyzerV3({
version: '2017-09-21',
iam_apikey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
url: 'https://gateway-lon.watsonplatform.net/tone-analyzer/api',
});
I don't see problem with code (also never used watson stuff), but you may check the following point :
How the request you really send is formated : Because I see that you send param that is not present in your curl request.
Is your function using POST aswell (you don't provide much detail on what the call to toneAnalyzer.tone does exactly) ? Maybe it's a conflict of headers or Content-Type.
Do you use a proxy (enterprise settings or stuff like that) ? If you do, you may check that node is correctly using it.
You should also provide a bit more details on what exactly your tone object do, and try to find where the call to the IBM API is done.

How to POST image as form data using npm request?

I have a specific task: I need to download an image from the source URL and upload it to another host via POST request as multipart/form-data. I'm trying to use node.js request library but never succeed.
The following code doesn't send anything in the request body.
request.post({
url: uploadUrl,
formData: {
photo: request(imageUri)
}
}, function (err) {
if (err) console.error(err.stack)
});
I have tried posting directly through the form-data library, but it doesn't seem to work neither. How do I solve this without the creation of temp files?
As i said in my comment, you need to wait until you have the image to make the post request. If you wanted to pipe the streams, you could try something like this...
request.get(imageUri).pipe(request.post(uploadUri));
Hope that helps.
The problem turned out to be that my imageUri had query parameters in it. I think this is a bug in form-data library. Removing query parameters solved the problem.

Node.js Express app with request module - Upload image to CouchDB using PUT

I am using Mikeal's request module to talk to the CouchDB HTTP API from an Express app. I can't use any other modules (such as nano) as this an academic project.
What I would like to do is get an image file, that has been uploaded from a form in a web app, and save it to my Couch as an attachment. To do this using curl is very simple:
curl -vX PUT http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg?rev=2-2739352689
--data-binary #artwork.jpg -H "Content-Type: image/jpg"
What I can't wrap my head around is how to structure the PUT request using the request module. Express stores the file temporarily in the directory
/tmp/{doc._id}.jpg
How do I get the file from there to my couch? Pretty desperate here.
I haven't verified this, but you might be able to do this:
var
fs = require('fs'),
request = require('request'),
url = 'http://admin:password#127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg?rev=2-2739352689';
var requestStream = request.put(url);
requestStream.on('response', function (response) {
console.log(response);
});
fs.createReadStream('image.jpg').pipe(requestStream);

Use NodeJS to upload file in an API call

I'm looking at using NodeJS to act as the server to build an API.
Ideally I'd love for there to be an API endpoint to send a set of information as well as a file which can be saved to the files system.
Most examples I've seen are for sending a file via a form, however I'd like to do this through a post request.
Does anyone know how I could achieve this (if it's at all possible)?
At the moment what I'd like to achieve is something along the following lines:
app.post('/Some/Endpoint/', controller.handleSomeEndpoint, function(request, response) {
response.send('Finished Request');
});
exports.handleSomeEndpoint = function(request, response, next) {
var bodyarr = []
request.on('data', function(chunk){
bodyarr.push(chunk);
})
request.on('end', function(){
console.log( bodyarr.join('') );
})
}
But the data and end never get called if I run a curl command along the lines of:
curl http://127.0.0.1:5000/Some/Endpoint/ -F 'test=#test_file'
Cheers,
Matt
The answer seems to be that expressJS doesn't use the same method of handling a post file as the http module in nodejs.
All that was needed was including a directory for the files to be written to:
app.use(express.bodyParser({uploadDir:'./uploads'}));
Which I found here:
http://www.hacksparrow.com/handle-file-uploads-in-express-node-js.html
I would suggest you to use Formidable to avoid anonymous file uploading.
Your code should work fine; it's the curl usage that's wrong. Try this instead:
$ curl -X POST --data-binary #test_file http://localhost:8080

Resources