I must confess I'm stuck. I need a nodejs app to download a file from a SharePoint library. Simple, huh? No. Not the simple OOTB SharePoint. The only-ssl allowed, with specific mandatory header added and surely only domain-based NTLM authentication method.
I've tried httpntlm (https://www.npmjs.org/package/httpntlm) that seemed to just might work in advance, but no. The SP responses with something went wrong message.
I've tried node-sharepoint, but it doesn't support NTLM yet. The app gets ETIMEDOUT response.
Any ideas, please welcome.
I am able to download the file using httpntlm module.you need to change the few lines of code.Replace the waterfall logic with below code in httpntlm.js.
async.waterfall([
function ($){
var type1msg = ntlm.createType1Message(options);
httpreq.get(options.url, {
headers:{
'Connection' : 'keep-alive',
'Authorization': type1msg
},
agent: keepaliveAgent
}, $);
},
function (res, $){
if(!res.headers['www-authenticate'])
return $(new Error('www-authenticate not found on response of second request'));
var type2msg = ntlm.parseType2Message(res.headers['www-authenticate']);
var type3msg = ntlm.createType3Message(type2msg, options);
if(method!=='download'){
httpreq[method](options.url, {
headers:{
'Connection' : 'Close',
'Authorization': type3msg
},
allowRedirects: false,
agent: keepaliveAgent
}, $);
}else{
//By Dheeraj for file download
httpreq.download(
url,
{
headers:{
'Connection' : 'Close',
'Authorization': type3msg
},
//allowRedirects: false,
agent: keepaliveAgent
},
__dirname + 'your_filename',
function (err, progress){
if (err) return console.log(err);
console.log(progress);
}, function (err, res){
if (err) return console.log(err);
console.log(res);
});
}
}
], callback);
};
['get', 'put', 'post', 'delete', 'head','download'].forEach(function(method){
exports[method] = exports.method.bind(exports, method);
});
and replace download method of httpreq.js(httpntm_module/node_modules/httpreq_module/httpreq.js) You can find it at Line number 79 approx.
exports.download = function (url,options, downloadlocation, progressCallback, callback) {
//var options = {};
options.url = url;
options.method = 'GET';
options.downloadlocation = downloadlocation;
options.allowRedirects = true;
// if only 3 args are provided, so no progressCallback
if(callback === undefined && progressCallback && typeof(progressCallback)==="function")
callback = progressCallback;
else
options.progressCallback = progressCallback;
doRequest(options, callback);
}
Please let me know if you are still getting issues.
Related
I am trying to call a REST API endpoint from node.js, using the 'request'module. I keep getting a 401 invalid credentials response. Code is as follows:
var q = {
'boothNumber':'1400',
'databaseName':'demo',
'exhibitorId':'T19',
'comment':'N/A'
};
var options = {
url: 'https://api2.e-----d.com',
path: '/edgewebapi/ACTDev2/booths/hold',
method: 'PUT',
//headers: headers,
headers: { 'Authorization':'Basic VUdFUTdDZkY6RmJsb0QyWiQ='},
body: JSON.stringify(q)
}
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log('Request successful.');
}
else {
console.log('Error = ' + error) ;
}
})
I have read every post on this site to try to solve it, tried every suggestion, including the 'auth' option below (in a headers object):
I tried using a headers object (below):
var headers = {
'Accept': 'application/json',
'Authorization': 'Basic VUdFUTdDZkY6RmJsb0QyWiQ='
/*
'auth': {
'user': 'UGEQ7CfF',
'pass': 'FbloD2Z$',
'sendImmediately': false
}
*/
}
I retried using axios, code below, and everything works. (I really need to keep using the request module though, because I am using this in AWS Lambda and the axios causes me other issues...):
axios.put(
'https://api2.e---d.com/edgewebapi/ACTDev2/booths/hold?boothNumber=1400&databaseName=demo&exhibitorId=T19',
{},
{ headers : {'Authorization': 'Basic VUdFUTdDZkY6RmJsb0QyWiQ=' } }
).then(function(response) {
console.log(response.status);
}).catch(function(error) {
console.log(error);
});
Can anyone help by providing the correct code to do this? I have spent days trying to figure it out. Thanks.
I'm using NodeJS to call the new MailChimp 3.0 API in order to add an email to a list. While I can get it working via POSTman, I'm having a hard time with Node's http:
var http = require('http');
var subscriber = JSON.stringify({
"email_address": "test#test.com",
"status": "subscribed",
"merge_fields": {
"FNAME": "Tester",
"LNAME": "Testerson"
}
});
var options = {
host: 'https://us11.api.mailchimp.com',
path: '/3.0/lists/<myListID>/members',
method: 'POST',
headers: {
'Authorization': 'randomUser myApiKey',
'Content-Type': 'application/json',
'Content-Length': subscriber.length
}
}
var hreq = http.request(options, function (hres) {
console.log('STATUS CODE: ' + hres.statusCode);
console.log('HEADERS: ' + JSON.stringify(hres.headers));
hres.setEncoding('utf8');
hres.on('data', function (chunk) {
console.log('\n\n===========CHUNK===============')
console.log(chunk);
res.send(chunk);
});
hres.on('end', function(res) {
console.log('\n\n=========RESPONSE END===============');
});
hres.on('error', function (e) {
console.log('ERROR: ' + e.message);
});
});
hreq.write(subscriber);
hreq.end();
Rather than getting even some sort of JSON error from Mailchimp, however, I'm getting HTML:
400 Bad Request
400 Bad Request
nginx
Is it clear at all what I"m doing wrong here? It seems pretty simple, yet nothing I've tried seems to work.
A few additional thoughts:
While http's options have an "auth" property, I'm using the headers instead to ensure the authorization is sent without the encoding (as mentioned here). Still, I've also tried with the "auth" property, and I get the same result.
I'm actually making this call from inside an ExpressJS API (my client calls the Express API, that calls the above code - I've edited all that out of this example for simplicity). That's why my variables are "hres" and "hreq", to distinguish them from the "res" and "req" in Express. Is there any reason that could be the issue?
As mentioned above, I am able to get successful results when using POSTman, so I at least know my host, path, list ID, and API key are correct.
It turns out this had a very simple solution: the "host" property of the options object needed to have only the domain name. IE, remove the "https://" protocol:
var options = {
host: 'us11.api.mailchimp.com',
path: '/3.0/lists/<myListID>/members',
method: 'POST',
headers: {
'Authorization': 'randomUser myApiKey',
'Content-Type': 'application/json',
'Content-Length': subscriber.length
}
}
Try this , its working fine for Me.
var request = require('request');
function mailchimpAddListCall(email, cb){
var subscriber = JSON.stringify({
"email_address": email,
"status": "subscribed"
});
request({
method: 'POST',
url: 'https://us13.api.mailchimp.com/3.0/lists/<Your list id>/members',
body: subscriber,
headers:
{
Authorization: 'apikey <your Mailchimp API key>',
'Content-Type': 'application/json'
}
},
function(error, response, body){
if(error) {
cb(err, null)
} else {
var bodyObj = JSON.parse(body);
console.log(bodyObj.status);
if(bodyObj.status === 400){
cb(bodyObj.detail, null);
}
var bodyObj = JSON.parse(body);
cb(null, bodyObj.email_address +" added to list.");
}
});
}
request is a node module, that you'll need to install into your package.json. npm install --save request
You can use the auth properties just fine with API v3, but if you're getting a 400, that's not the problem. The body of the 400 Error should provide more detailed information, but one thing that jumps out immediately: MailChimp doesn't allow fake or fake-looking emails to be added to lists (like test#test.com), so I'd try a real address and see if that works for you.
I am trying to automatically post some assets on a Github release I programmatically create.
Here is my upload function:
function uploadFile(fileName, uploadUrl, callback){
var uploadEndPoint = url.parse(uploadUrl.substring(0,uploadUrl.indexOf('{')));
options.host = uploadEndPoint.hostname;
options.path = uploadEndPoint.pathname+'?name=' + fileName;
options.method = 'POST';
options.headers['content-type'] = 'application/zip';
var uploadRequest = https.request(options, callback);
uploadRequest.on('error', function(e) {
console.log('release.js - problem with uploadRequest request: ' + e.message);
});
var readStream = fs.ReadStream(path.resolve(__dirname,'builds',fileName));
readStream.pipe(uploadRequest);
readStream.on('close', function () {
req.end();
console.log('release.js - ' + fileName + ' sent to the server');
});
}
At the end of this I get a 404 not found
I tried auth from token and user/password
I checked the url
I though it might be because of SNI, but I don't know how to check that.
Any clue ? Thanks !
I found a solution to that problem by NOT using the low level node.js modules and using instead restler which is a library that handles SNI.
Here is how is used it:
rest = require('restler'),
path = require('path'),
fs = require('fs');
fs.stat(path.resolve(__dirname,'builds',fileName), function(err, stats){
rest.post(uploadEndPoint.href+'?name=' + fileName, {
multipart: true,
username: GITHUB_OAUTH_TOKEN,
password: '',
data: rest.file(path.resolve(__dirname,'builds',fileName), null, stats.size, null, 'application/zip')
}).on('complete', callback);
});
Hope that will help someone :)
EDIT on 27/02/2015: We recently switched from restler to request.
var
request = require('request'),
fs = require('fs');
var stats = fs.statSync(filePath);
var options = {
url: upload_url.replace('{?name}', ''),
port: 443,
auth: {
pass: 'x-oauth-basic',
user: GITHUB_OAUTH_TOKEN
},
json:true,
headers: {
'User-Agent': 'Release-Agent',
'Accept': 'application/vnd.github.v3+json',
'Content-Type': 'application/zip',
'Content-Length': stats.size
},
qs: {
name: assetName
}
};
// Better as a stream
fs.createReadStream(filePath).pipe(request.post(options, function(err, res){
// Do whatever you will like with the result
}));
The upload_uri can be retrieved through a get request on an existing release or in the response directly after the release creation.
I am trying to post a task in asana with the following node/express function
exports.addTask = function(req, res) {
var url ='/api/1.0/tasks?workspace=' + req.session.workspace_id
var postBase = "app.asana.com";
var options = {
host: postBase,
port: 443,
path: url,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + JSON.parse(req.session.user).access_token,
}
};
var req2 = https.request(options, function(res2) {
res2.on('data', function(chunk) {
console.log(chunk + "");
});
res2.on('error', function(e){
console.log(e.message);
});
});
req2.end();
}
I get the correct response back from asana which is:
{"data":{"id":8253508011735,"created_at":"2013-10-20T16:17:53.140Z","modified_at":"2013-10-20T16:17:53.140Z","name":"","notes":"","completed":false,"assignee_status":"upcoming","completed_at":null,"due_on":null,"workspace":{"id":1361701377437,"name":"getspur.com"},"assignee":null,"parent":null,"followers":[{"id":1050147548705,"name":"Gorkem Yurtseven"}],"projects":[],"tags":[]}}
but nothing seems to be added in my asana tasks..
ps. I am currently at the Facebook Hackathon in New York,so bring it on!
It could be because the assignee is null, and it's not in any projects - that basically makes it impossible to find (except perhaps via Search?)
Without seeing the post body I'm not sure if that's intentional or just a formatting issue.
I'm trying to implement https://developers.podio.com/doc/items/add-new-item-22362 Podio API addItem call in a nodejs module. Here is the code:
var _makeRequest = function(type, url, params, cb) {
var headers = {};
if(_isAuthenticated) {
headers.Authorization = 'OAuth2 ' + _access_token ;
}
console.log(url,params);
_request({method: type, url: url, json: true, form: params, headers: headers},function (error, response, body) {
if(!error && response.statusCode == 200) {
cb.call(this,body);
} else {
console.log('Error occured while launching a request to Podio: ' + error + '; body: ' + JSON.stringify (body));
}
});
}
exports.addItem = function(app_id, field_values, cb) {
_makeRequest('POST', _baseUrl + "/item/app/" + app_id + '/',{fields: {'title': 'fgdsfgdsf'}},function(response) {
cb.call(this,response);
});
It returns the following error:
{"error_propagate":false,"error_parameters":{},"error_detail":null,"error_description":"No matching operation could be found. No body was given.","error":"not_found"}
Only "title" attribute is required in the app - I checked that in Podio GUI. I also tried to remove trailing slash from the url where I post to, then a similar error occurs, but with the URL not found message in the error description.
I'm going to setup a proxy to catch a raw request, but maybe someone just sees the error in the code?
Any help is appreciated.
Nevermind on this, I found a solution. The thing is that addItem call was my first "real"-API method implementation with JSON parameters in the body. The former calls were authentication and getApp which is GET and doesn't have any parameters.
The problem is that Podio supports POST key-value pairs for authentication, but doesn't support this for all the calls, and I was trying to utilize single _makeRequest() method for all the calls, both auth and real-API ones.
Looks like I need to implement one for auth and one for all API calls.
Anyway, if someone needs a working proof of concept for addItem call on node, here it is (assuming you've got an auth token beforehand)
_request({method: 'POST', url: "https://api.podio.com/item/app/" + app_id + '/', headers: headers, body: JSON.stringify({fields: {'title': 'gdfgdsfgds'}})},function(error, response, body) {
console.log(body);
});
You should set content-type to application/json
send the body as stringfied json.
const getHeaders = async () => {
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
};
const token = "YOUR APP TOKEN HERE";
headers.Authorization = `Bearer ${token}`;
return headers;
}
const createItem = async (data) => {
const uri = `https://api.podio.com/item/app/${APP_ID}/`;
const payload = {
fields: {
[data.FIELD_ID]: [data.FIELD_VALUE],
},
};
const response = await fetch(uri, {
method: 'POST',
headers: await getHeaders(),
body: JSON.stringify(payload),
});
const newItem = await response.json();
return newItem;
}