Node / Javascript - pipe writeStream / file to post request - javascript

I have the following code, it creates a file on a remote server from a test var (just to make sure it worked), but now I need to upload a file and I'm not sure how to actually attach it to the request, here is the code:
var dataString = '#test.txt';
var options = {
uri: 'https://site.zendesk.com/api/v2/uploads.json?filename=test.txt',
method: 'POST',
headers: {
'Content-Type': 'application/binary',
'Accept': 'application/json',
Authorization: 'Basic bXVydGV6LmF....'
},
body: dataString
//this will create a test file with some text, but I need
//to upload a file on my machine instead
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
var x = {
error: error,
response: response,
body: body
}
console.log(x);
}
request(options, callback);
I was thinking something in the lines of:
fs.createReadStream('text.txt').pipe({function?})
But I'm not sure how to finish this part unfortunately.
update: 2019
It's been a LONG time, but someone asked for the solution. I'm not sure if this is how I fixed it tbh or if this code even works, but I found this digging around, give it a try.
Also, Zendesk updated their API at some point, not sure when exactly so this may be old anyways:
var uploadAttachment = function() {
var uOptions = {
uri: 'xxx/api/v2/uploads.json?filename=' + fileName,
method: 'POST',
headers: {
'Content-Type': 'application/binary',
'Accept': 'application/json',
Authorization: 'Basic xxx'
}
};
function callback(error, response, body) {
if (!body) {
if (error) {
return next(error);
} else {
var x = {
error: true,
message: "Some message",
err: response
};
return next(x);
}
}
if (body && body.error) {
return next(error);
}
if (error) {
return next(error);
}
var jr = JSON.parse(body);
var uploaded = {};
if (jr.upload) {
uploaded = jr.upload;
}
attachToComment(uploaded);
}
fs.createReadStream(tempPath + fileName).pipe(request(uOptions, callback));
};
I hope this helps, sorry in advance if it does not work, I no longer have access to zendesk.

Related

How to wait until request.get finish then conduct the next block in node.js

I am new to NodeJS and I am working on a request.get problem. My goal is simply have a function that request the web, and when request finished, the function returns the result, otherwise it returns an error message.
Here's the function that I used for request:
var artistNameIdMap = {};
var getPopularArtists = async () => {
//https://nodejs.org/api/http.html#http_http_request_options_callback
var options = {
url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
headers: { 'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'},
json: true
}
request.get(options, function(error, response, body) {
if (response.statusCode === 200){
console.log("inside");
artistNameIdMap = getArtistNameIdMap(body, artistNameIdMap);
} else {
res.send("get popular error");
return {};
}
})
console.log("outside");
return artistNameIdMap;
module.exports = {
GetPopularArtists: getPopularArtists
}
And this function is included in a getPopular.js file. I would like to call the function in another file playlist.js.
In playlist.js, I wrote
const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", (req, res) =>{
const artistNameIdMap = getPopular.GetPopularArtists();
console.log(artistNameIdMap);
let BPM = req.params.BPM;
res.send(BPM);
})
However the result I got is
outside
Promise { {} }
inside
It seems like the return was before the request gives back the information. I wonder what should I write to make sure that I can obtain the correct artistNameIdMap at playlist.js.
Though you've already accepted an answer, there are a couple of additional things I can add. First, the request() library has been deprecated and it is not recommended for new code. Second, there is a list of recommended alternatives here. Third, all these alternatives support promises natively as that is the preferred way to program asynchronous code in modern nodejs programming.
My favorite alternative is got() because I find it's interface simple and clean to use and it has the features I need. Here's how much simpler your code would be using got():
const got = require('got');
let artistNameIdMap = {};
async function getPopularArtists() {
const options = {
headers: { 'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'},
};
const url = CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath;
let results = await got(url, options).json();
// update local cache object
artistNameIdMap = getArtistNameIdMap(results, artistNameIdMap);
return artistNameIdMap;
}
module.exports = {
GetPopularArtists: getPopularArtists
}
Note: The caller should supply error handling based on the returned promise.
GetPopularArtists().then(results => {
console.log(results);
}).catch(err => {
console.log(err);
});
Since you want to use Promises, use it like this
const getPopularArtists = () => new Promise((resolve, reject) {
const options = {
url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
headers: {
'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
json: true
}
request.get(options, (error, response, body) => {
if (error) {
reject(error);
} else if (response.statusCode === 200) {
console.log("inside");
resolve(getArtistNameIdMap(body, artistNameIdMap));
} else {
reject("get popular error");
}
});
});
module.exports = {
GetPopularArtists: getPopularArtists
}
And use it like
const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", async (req, res) =>{
try {
const artistNameIdMap = await getPopular.GetPopularArtists();
console.log(artistNameIdMap);
let BPM = req.params.BPM;
res.send(BPM);
} catch(err) {
res.send(err);
}
})
Alternatively, without promises, you'll need to use a callback
Using callbacks:
const getPopularArtists = (callback) => {
const options = {
url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
headers: { 'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'},
json: true
}
request.get(options, function(error, response, body) {
if (error) {
callback(error);
} else if (response.statusCode === 200){
console.log("inside");
callback(null, getArtistNameIdMap(body, artistNameIdMap));
} else {
callback("get popular error");
}
})
};
module.exports = {
GetPopularArtists: getPopularArtists
}
And use it like:
const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", (req, res) =>{
getPopular.GetPopularArtists((err, artistNameIdMap) => {
if (err) {
// handle error here
} else {
console.log(artistNameIdMap);
let BPM = req.params.BPM;
res.send(BPM);
}
});
});

Why, when I make an http call, do I get an error saying my url is not a string?

The config file contains an object:
var config = {
uri: 'https://localhost:1234',
postcodeTimeoutMillsecs: process.env.POSTCODE_TIMEOUT || 3000
};
module.exports = config;
My http call gives me an error saying my must be a string, which I'm pretty sure it is. The console.log tells me I'm passing 'http://localhost:1234', which is what I expect.
const fs = require('fs');
const config = require('../config/config');
const defaultHttp = require('axios');
const ono = require('ono');
exports.submitApplication = (data) => {
console.log('config.uri=');
console.log(config.uri);
return new Promise((resolve, reject) => {
let http = defaultHttp;
http.options({
method: 'post',
url: config.uri,
data: data,
headers: {
'Content-Type': 'application/json'
},
}).then(function (response) {
resolve(response);
}).catch(function (error) {
var submissionErr;
if (error.type === 'http') {
// error received from DRSI Communicator
submissionErr = ono({ status: error.code },
'Submission failed - ' + error.toString() +
' - ' + (error.body.message || error.body.errors.join()));
console.log(submissionErr);
} else {
submissionErr = ono({ status: 503 },
'Submission failed - internal connectivity problem - ' + error.toString());
}
submissionErr.errorType = 'submission-failure';
reject(submissionErr);
});
});
};
The full error message is:
message: 'Submission failed - internal connectivity problem - TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received an instance of Object'
Any idea where I’m going wrong?
It seems like you are using the wrong method.
The argument list for http.options is: axios.options(url[, config]).
http.options({
method: 'post',
url: config.uri,
data: data,
headers: {
'Content-Type': 'application/json'
},
})
should probably be
http({
method: 'post',
url: config.uri,
data: data,
headers: {
'Content-Type': 'application/json'
},
})
or
http.post(config.uri, data {
headers: {
'Content-Type': 'application/json'
},
})
Source:
https://github.com/axios/axios#axiosoptionsurl-config

Novice friendly way of calling two functions sequentially in JS

Sorry to ask a question that seems to have been answered at length in countless ways, I understand the asynchronous nature of JS, but the countless treatises on promises and callbacks I've read hasn't helped me produce working code.
I have 2 functions that interact with an API, and I just want to be able to call them in a way where one will run after the other.
These are my two functions:
let pveNextid = "";
function getNextID() {
var clientServerOptions = {
method: 'GET',
uri: apiRoot + "/cluster/nextid",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
}
}
request(clientServerOptions, function(error, response) {
pveNextid = JSON.parse(response.body).data;
console.log("Next VMID: " + pveNextid);
})
}
// Create a new container with specs defined in conf.js
function newContainer() {
var clientServerOptions = {
method: 'POST',
uri: apiRoot + "/nodes/" + conf.pveNode + "/lxc",
form: {
net0: "bridge=vmbr0,name=eth0,ip6=auto",
ostemplate: conf.pveTemplate,
vmid: pveNextid,
unprivileged: 1,
storage: "local-lvm",
memory: 320,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
'CSRFPreventionToken': pveCSRF,
}
}
request(clientServerOptions, function(error, response) {
console.log(response.body);
})
};
There must be a simple, as in a few readable lines, way of doing this?
The simplest way would be to provide a callback to the functions to give you a hook to run some code after the request completes, you can get rid of the global variable too this way:
// Take a callback here
function getNextID(callback) {
var clientServerOptions = {
method: 'GET',
uri: apiRoot + "/cluster/nextid",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
}
}
request(clientServerOptions, function(error, response) {
var pveNextid = JSON.parse(response.body).data;
console.log("Next VMID: " + pveNextid);
// call the callback and give it the information you want to provide to the function
callback(pveNextid);
})
}
// Create a new container with specs defined in conf.js
// take the pveNextid here
function newContainer(pveNextid) {
var clientServerOptions = {
method: 'POST',
uri: apiRoot + "/nodes/" + conf.pveNode + "/lxc",
form: {
net0: "bridge=vmbr0,name=eth0,ip6=auto",
ostemplate: conf.pveTemplate,
vmid: pveNextid,
unprivileged: 1,
storage: "local-lvm",
memory: 320,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
'CSRFPreventionToken': pveCSRF,
}
}
request(clientServerOptions, function(error, response) {
console.log(response.body);
})
};
// call getNextId and provide the callback here that you want to run after the first request
getNextId(newContainer);
I'd suggest promises and async/await and other more maintainable solutions over callbacks all the way down, however in this case it is a simple solution.

Using JavaScript Fetch with Formidablejs, Expressjs

I'm using Reactjs saga to send a post request using fetch. Also I'm trying to use formidable instead of usual body-parser. I'm getting weird parsing issues. What am I doing wrong?
// saga simplified piece of code
const { loginEmail, loginPwd } = request.payload;
let postLoginSubmitOptions = {
method: "POST",
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type' : 'application/x-www-form-urlencoded'
},
body: JSON.stringify({
loginEmail: loginEmail,
loginPwd: loginPwd
})
};
const response = yield call(fetch, `http://www.example.com/register`, postLoginSubmitOptions);
// expressjs side, simplified view
router.post('/register', function(req, res, next) {
console.log('registering user');
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if(err){
console.log(err);
}
console.log(`incoming fields via form parse`);
console.log(fields); // { '{"loginEmail":"my-email#gmail.com","loginPwd":"my-password"}': '' }
console.log(fields.loginEmail); // undefined
});
}
pass content type as json
let postLoginSubmitOptions = {
method: "POST",
headers: new Headers({'content-type': 'application/json'}),
body: JSON.stringify({
loginEmail: loginEmail,
loginPwd: loginPwd
})
};
I don't know where exactly the problem was but tried encoding data differently and then it worked. Getting a nice parsed object now with formidable: { loginEmail: 'dan#dan.com', loginPwd: 'asjdfkjsadlf' }
function sendData(data) {
const { loginEmail, loginPwd } = request.payload;
const body = { loginEmail, loginPwd };
var urlEncodedData = "";
var urlEncodedDataPairs = [];
var name;
for(name in body) {
urlEncodedDataPairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(body[name]));
}
urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+');
var httpHeaders = {
'Content-Type' : 'application/x-www-form-urlencoded',
'Accept' : 'application/json'
}
let postOptions = {
method: 'post',
headers: new Headers(httpHeaders),
/*mode: 'no-cors',*/
body: urlEncodedData
};
try {
const response = yield call(fetch, `http://www.example.com/register`, postOptions);
const data = yield call([response, response.json]);
console.log(`data returned by fetch`);
console.log(data);
yield put({type: 'LOGIN_SUBMIT_RESPONSE', payload: data.message})
} catch (e) {
console.log(`error fetch post object`);
}
}
Thanks everyone!

JSON Request works in Javascript but not in Nodejs (statusCode: 403)

I want to request a simple JSON File in NodeJS. With Javascript and jQuery it works like a charm:
$(document).ready(function() {
$.getJSON('https://www.younow.com/php/api/broadcast/info/curId=0/user=Peter', function(json) {
if (json["errorCode"] > 0) {
console.log("Offline");
$('#ampel').addClass('red');
} else {
console.log("Online");
$('#ampel').addClass('green');
}
});
})
But i can't get it to work with NodeJS:
var request = require('request');
var options = {
url: 'https://www.younow.com/php/api/broadcast/info/curId=0/user=Peter',
headers: {
'content-type': 'application/javascript'
}
};
function callback(error, response, body) {
console.log(response.statusCode);
}
request(options, callback);
The StatusCode is always 403 and i can't work with the data. Can somebody help me, so i can get the same result like with jQuery?
Thanks!
I was able to find the solution with Mike McCaughan's help:
I had to send a different user-agent to get a 200 response. The code looks like this now:
var options = {
url: 'https://www.younow.com/php/api/broadcast/info/curId=0/user=',
headers: {
'User-Agent': 'request'
}
};
function callback(error, response, body) {
var str = JSON.parse(body);
if (str.errorCode > 0) {
...
} else {
...
}
}
request(options, callback);

Categories

Resources