calling external rest api from node without encoding querystring params - node.js

I am trying to call an external rest API from node server by using request node module.
let request = require('request');
var options = {
method: 'POST',
url: 'https://somerestURI:3000',
qs: { msg: 'some|data|for|other|server' }
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
If I try to run the above code, query string value is being encoded to
some%7cdata%7cfor%7cother%7cserver
as a result I am not receiving correct response.
But if I fire the same request in POSTMAN. I am receiving the expected output(I think postman is not encoding query string).
So what I want is don't encode the query string value.
Any help would be greatly appreciated.

As answered here, you can disable encoding in qsStringifyOptions
var options = {
method: 'POST',
url: 'https://somerestURI:3000',
qs: { msg: 'some|data|for|other|server' },
qsStringifyOptions: {
encoding: false
}
};

You can use node-rest-client package. It allows connecting to any REST API and get results as javascript Object.
var HttpClient = require('node-rest-client').Client;
var httpClient = new HttpClient();
// GET Call
httpClient.get("http://remote.site/rest/xml/method", function (data, response) {
// parsed response body as js object
console.log(data);
// raw response
console.log(response);
});)
or for POST Call
var args = {
data: { test: "hello" },
headers: { "Content-Type": "application/json" }
};
//POST Call
httpClient.post("http://remote.site/rest/xml/method", args, function (data, response) {
// parsed response body as js object
console.log(data);
// raw response
console.log(response);
});

Related

In Node.js, why doesn't the request package perform basic authentication?

I have set up a test end point here:
https://9wi46s5jzc.execute-api.us-east-1.amazonaws.com/test
For some baseline testing, I go to apitester.com and run two tests:
Firstly, a post request to: https://admin:password#9wi46s5jzc.execute-api.us-east-1.amazonaws.com/test (correct credentials) gives me output of:
{"isBase64Encoded":false,"statusCode":401,"headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"0","etag":"W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\""},"body":""}
Secondly, a post request to: https://admin:BADPASSWORD#9wi46s5jzc.execute-api.us-east-1.amazonaws.com/test (incorrect credentials) gives me output of:
{"message":"Unauthorized"}
So they're the baseline tests for what should happen.
When I run the following code:
const request = require('request');
const url = 'https://admin:password#9wi46s5jzc.execute-api.us-east-1.amazonaws.com/test';
request.post(url, function(err, res, body) {
console.log("body", body);
});
I get:
body {"message":"Unauthorized"}
Why is this happening?
According to the docs:
https://github.com/request/request
this is the way to do basic authentication.
So I'm expecting correct authorization but I'm not getting it. What am I doing wrong?
You should try it using this :
const proxyUrl = 'https://admin:password#9wi46s5jzc.execute-api.us-east-1.amazonaws.com/test';
const proxyRequest = request.defaults({ 'proxy': proxyUrl});
const options = {
url: '...',
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer " + token // if this is how you handle auth and you already have the token
}
};
proxyRequest .get(options, function (error, response, body) {
if (error) {
next(error); // if you're using Express
}
console.log("body", body);
});

Send unparsed data in a Node JS request

I want to send a POST request (for example, with the 'request' module), but I don't find a way of sending unparsed data*.
*unparsed data => copied directly from the Chrome dev tool. Something like: tipo_accion=3&filtro=descarga&fecha=actual
It would also do the trick some way of translating that string to JSON.
I've tried so far with...
var request = require('request');
request.post({ url: 'https://target.com/form/', form: 'tipo_accion=3&filtro=descarga&fecha=actual' },
function (error, response, body) {
console.log(body)
}
);
... but it didn't work.
Firstly you should understand the difference between the request methods post and get.
The structure that you want to send:
tipo_accion=3&filtro=descarga&fecha=actual is telling me that you want to use a get request. So the proper code for that will be something like:
request(
'https://target.com/form/&tipo_accion=3&filtro=descarga&fecha=actual',
function (error, response, body) {
console.log(body)
},
);
But if it is a post request then you should use the json format
request.post({
url: 'https://target.com/form/', form: {
tipo_accion: 3,
filtro: 'descarga',
fecha: 'actual'
},
function(error, response, body) {
console.log(body)
}
);
You can convert form_data to string format and it works for me you can try it :
const request = require('request-promise');
var j = request.jar()
var data_fom = `a=value_a&b=value_b&c=value_c`
request({
url:"https://target.com/form/",
jar:j,
method:"POST",
resolveWithFullResponse: true,
form:data_form
})

How to properly use putAsync after promisify request module

I searched here and there and ended up with no finding regarding putAsync method of promisified request by bluebird.
var request = require('request');
var Promise = require('bluebird');
Promise.promisifyAll(require("request"));
request.putAsync({
uri: buApiUrl,
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
name: BU,
workstations: formattedWorkStaions[BU]
})
}).spread(function (response, body) {
debugHelper.log(body);
}).catch(function (err) {
debugHelper.error(err);
});
Above is the code snippet that is in my program. And it does not send put request. While using postAsync, if will send post request successfully.
Can anyone help explain why?
I already found the part where is wrong in the putAsync code snippet. I should use json not body as the key for the payload. And the payload does not need to be stringified.
Here is the new code snippet proven to work.
var request = require('request');
var Promise = require('bluebird');
Promise.promisifyAll(require("request"));
request.putAsync({
uri: buApiUrl,
headers: {
'content-type': 'application/json'
},
json: {
name: BU,
workstations: formattedWorkStaions[BU]
}
}).spread(function (response, body) {
debugHelper.log(body);
}).catch(function (err) {
debugHelper.error(err);
});
This is quite tricky and result in my second question.
Why there is such a difference between post and put other than their method type?

Podio API addItem call

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;
}

invalid oauth2 token request

I'm developing a node application which needs to authenticate with google. When I request a token, https://accounts.google.com/o/oauth2/token responds with:
error: 400
{
"error" : "invalid_request"
}
I've tried making the same request in curl, and have received the same error, so I suspect there is something wrong with my request but I can't figure out what. I've pasted my code below:
var request = require('request');
var token_request='code='+req['query']['code']+
'&client_id={client id}'+
'&client_secret={client secret}'+
'&redirect_uri=http%3A%2F%2Fmassiveboom.com:3000'+
'&grant_type=authorization_code';
request(
{ method: 'POST',
uri:'https://accounts.google.com/o/oauth2/token',
body: token_request
},
function (error, response, body) {
if(response.statusCode == 201){
console.log('document fetched');
console.log(body);
} else {
console.log('error: '+ response.statusCode);
console.log(body);
}
});
I've triple checked to make sure all the data I'm submitting is correct and i'm still getting the same error. What can I do to debug this further?
It turns out that request.js (https://github.com/mikeal/request) doesn't automatically include the content-length to the headers. I added it manually and it worked on the first try. I've pasted the code below:
exports.get_token = function(req,success,fail){
var token;
var request = require('request');
var credentials = require('../config/credentials');
var google_credentials=credentials.fetch('google');
var token_request='code='+req['query']['code']+
'&client_id='+google_credentials['client_id']+
'&client_secret='+google_credentials['client_secret']+
'&redirect_uri=http%3A%2F%2Fmyurl.com:3000%2Fauth'+
'&grant_type=authorization_code';
var request_length = token_request.length;
console.log("requesting: "+token_request);
request(
{ method: 'POST',
headers: {'Content-length': request_length, 'Content-type':'application/x-www-form-urlencoded'},
uri:'https://accounts.google.com/o/oauth2/token',
body: token_request
},
function (error, response, body) {
if(response.statusCode == 200){
console.log('document fetched');
token=body['access_token'];
store_token(body);
if(success){
success(token);
}
}
else {
console.log('error: '+ response.statusCode);
console.log(body)
if(fail){
fail();
}
}
}
);
}
from here How to make an HTTP POST request in node.js? you could use querystring.stringify to escape query string of request parameters. Plus you'd better add 'Content-Type': 'application/x-www-form-urlencoded' for POST request.
post here the final string generated from token_request var.that may have something wrong. or may be authentication code is expired or not added correctly to the URL. Usually code has '/' in it that needs to escaped.

Resources