nodejs set encoding of body using request module - node.js

I have to send a post request with a body containing russian characters to a service which seems to only accept win1251 encoding. I am doing this in node.js using the request module.
This is how I am sending the request
var rawbody = "i1=&i2=&i3=" + query + "&i4=&i5=&i8=";
var options = {
url: this.initiate_endpoint,
jar: this.session,
cert: this.fs.readFileSync('resources/r.crt.pem', 'utf-8'),
key: this.fs.readFileSync('resources/r.key.pem', 'utf-8'),
timeout: 20000,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: rawbody
};
let cookie = this.session;
request.post(options,
function (error, response, body) {
if( error ) {
callback(cookie, error);
}
else if( response.statusCode !== 200 ) {
callback(cookie, 'Responded with status code: ' + response.statusCode);
}
else {
callback(cookie, false);
}
});
Whenever the query variable is containing russian letters the request will fail.
For example:
var query = 'Путин';
So my questions are how to actually convert the encoding from the query variable to win1251 and furthermore how to set the encoding of the actual raw postbody, because I think those two things could be the cause of the issue.

Related

Send a POST request with an image URL? --- Needle library

Trying to figure out the right way to send a RESTful request to an API using the Node.js Needle library. I think everything is right except the code concerning the image URL. No matter how I try to change what it looks like or where I put it, I keep getting an error that says it's an invalid image, but it's not, the URL is fine. So, my guess is my code is wrong and so whatever it thinks is the URL for the image, is probably not the URL (but maybe some other code or code in a location that should be where the body/image URL is).
const imageUrl = 'https://upload.wikimedia.org/wikipedia/commons/3/37/Dagestani_man_and_woman.jpg'
// Request parameters.
const params = {
returnFaceId: true,
returnFaceLandmarks: false,
returnFaceAttributes: 'age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise'
}
var options = {
body: '{"url": ' + '"' + imageUrl + '"}',
headers: {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': subscriptionKey
}
}
needle.post(endpoint, params, options, function (err, res, body) {
console.log(`Status: ${res.statusCode}`)
console.log('Body: ', body)
console.log('ERROR: ' + err)
//console.log(res)
})
I have also tried to write the body like a plain ol' object: body = { 'url': imageURL}, but still getting the same error.
Error:
Status: 400
Body: { error: { code: 'InvalidURL', message: 'Invalid image URL.' } }
Here is the API I am trying to call, which has been confirmed to work with other samples:
https://westus.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395236
For this request you have a combination of parameters:
Some of them as query strings (your 'params')
Some of them as a body payload (your options.body)
Therefore, it seems that you cannot use needle.post directly because it can do query string params OR body param but not both at the same time.
So there are several options:
Set your query string params in the URL field
Change your lib
For the 1st option, here is an example:
const imageUrl = 'https://upload.wikimedia.org/wikipedia/commons/3/37/Dagestani_man_and_woman.jpg'
// Request parameters.
const params = {
returnFaceId: true,
returnFaceLandmarks: false,
returnFaceAttributes: 'age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise'
}
// Adding params to query string
serialize = function(obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
endpoint = endpoint + "?" + serialize(params)
// Setting body and options
var body = '{ "url": ' + '"' + imageUrl + '"}'
var options = {
headers: {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': subscriptionKey
}
}
needle.post(endpoint, body, options, function (err, res, body) {
console.log(`Status: ${res.statusCode}`)
console.log('Body: ', body)
console.log('ERROR: ' + err)
//console.log(res)
})

retrieve JSON response of a POST request in nodeJS

I am sending s POST request to a service and it is supposed to return a JSON in response. I see the POST is successful but I dont get anything in response back. What am I missing? Below code
var headers = {
"Accept":"application/json",
"Content-Type":"application/json",
"Authorization": ("Basic " + new Buffer("admin:password").toString('base64'))
}
// Configure the request
var options = {
url: 'myservice-url',
method : 'POST',
headers : headers
}
// Start the request
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Print out the response body
var str = JSON.stringify(body, null, 2);
console.log(str)
}
})
First of all, need to confirm if you have properly installed the following:
https://github.com/request/request
Then require it in your file like this:
var request = require('request');
request.post({
url: "",//your url
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
rejectUnauthorized: false,//add when working with https sites
requestCert: false,//add when working with https sites
agent: false,//add when working with https sites
form: {
whateverfieldnameyouwant: "whatevervalueyouwant"
}
},function (response, err, body){
console.log('Body:',JSON.parse(body));
}.bind(this));

Images are not proxied correctly when using NodeJS + Request module

I have a proxy that works well (as far as I can tell) UNTIL I attempt to proxy images (or perhaps any binary data?). By my estimations, the below code should work, but it does not. I'm sure I"m doing something obviously dumb, but I've been digging through forums and apis and I have yet to hit upon the correct approach.
The 'core' of my proxy looks something like the following.
function(req, res) {
...
options = {
url: 'a url',
headers: {
'Authorization': auth
}
};
request(options,
function(e, r, b){
var encoding = (r.headers['content-type'].indexOf('image') === -1) ? 'utf8' : 'binary';
res.writeHead(200, {
'Content-Length': r.headers['content-length'],
'Content-Type': r.headers['content-type']
});
if (encoding === 'binary') {
b = new Buffer(b);
}
res.end(b, encoding);
});
}
What am I missing here?
Thanks in advance for any and all help!
My problem was not with the response (as I though originally), but rather the fact that the request module was encoding it's response body to unicode by default, when disabled (encoding: null), the response body is converted to a buffer which is easily consumed by the response.
options = {
url: url,
encoding: null,
headers: {
'Authorization': auth
}
};
request(options,
function(e, r, b){
var encoding = (r.headers['content-type'].indexOf('image') === -1) ? 'utf8' : 'binary';
res.end(b, encoding);
});

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