aacerox / node-rest-client Goto Github PK
View Code? Open in Web Editor NEWREST API client from node.js
License: MIT License
REST API client from node.js
License: MIT License
I'm building this request
DELETE /rest/service/5117 HTTP/1.1
Host: localhost:8080
Authorization: Basic bXl1c2VyOm15cGFzc3dvcmQ==
Cache-Control: no-cache
var Client = require('node-rest-client').Client
var defaultOptions = {
headers: [{"Content-Type": "application/json"}],
user: 'myuser',
password: 'mypassword',
mimetypes: {
json: ["application/json", "application/json;charset=utf-8"]
}
};
var client = new Client(defaultOptions);
client.delete('http://localhost:8080/rest/service/5117', function(data, response) { ... }); // always returns 400
if i use the module request works fine
var options = {
method: 'DELETE',
uri: 'http://localhost:8080/rest/service/5117',
headers: {"Content-Type": "application/json", "Authorization": "Basic bXl1c2VyOm15cGFzc3dvcmQ=="}
};
request(options, function(err, response, body) {....}); // works fine!
Unfortunately there are some services that I have to use which do not specify Content-Type header in the response.
Now It is pared as expected neither to json nor to xml.
Could you please add some option that allows to force to some Content-Type (or direct treat respose as json or xml) if no Content-Type in response.
When those two conditions are met (server sends an empty response, eg. with status 204 NO CONTENT
and with response header Content-Type
set to application/json
) the library will generate an exception. This is caused by function isJSON()
that does the check basing only on the Content-Type
header. Then, JSON.parse()
crashes when trying to parse empty string.
I'm trying to call Client using the next code:
Client = require('node-rest-client').Client;
var options = { protocol: "https"};
var client = new Client(options);
But I'm receiving the error below:
http.js:1604
throw new Error('Protocol:' + options.protocol + ' not supported.');
^
Error: Protocol:https: not supported.
at Object.exports.request (http.js:1604:11)
I'd really love to see support for Promises. Currently it's getting tedious to chain multiple calls. Support for bluebird promises would be be really nice.
Hello,
I am trying to show some log message when a post successfully completes and I am using the data
object passed to the POST callback. If I log the whole of data, then it shows ok, if I log only the data.name property , then it shows undefined. I include the code below.
If this the expected behaviour?
var Client = require('node-rest-client').Client;
var client = new Client();
var args = {
data: { name: "Jose",
fname: "Perez",
email: "[email protected]" , },
headers:{"Content-Type": "application/json"}
};
//console.log(i, rows[i].name);
client.post("http://localhost:3000/player", args, function(data,response) {
// This shows undefined ????
console.log(data.name);
// This shows OK
// {"id":10,"name":"Jose",....}
console.log(data);
});
Didn't see any examples but want to be sure I'm not overlooking anything. Thanks!
I was getting SSL errors when trying to use the url http://localhost:49664/v1
It looks like the options created in createConnectOptions() don't set a protocol (they do set host, port, path) and so subsequent tests of the options in "normal" and "proxy" assume the request should use https.
from createConnectOptions()
result ={
host: url.host.indexOf(":") == -1?url.host:url.host.substring(0,url.host.indexOf(":")),
port: url.port === undefined?defaultPort:url.port,
path: url.path
};
from "normal":function()
protocol = (options.protocol =="http")?http:https,
Express sets Content-Type as 'application/json; charset=utf-8' but the module has hardcoded the Content-Type as 'application/json;charset=utf-8'. Please add one with a space or use indexOf to look for application/json instead.
Hi there,
Whenever I'm issuing a http get request with keep-alive enabled I don't seem to be receiving an end or close event & the socket remains open. If I change the Connection header to be close it works fine.
Code snippet below. Any suggestions would be greatly appreciated.
client.get(url, args, function(data, response)
{
// Get response details
localrc = response.statusCode;
localsessKey = response.headers['my-session-key'];
if (doAuth == "yes")
{
if (typeof localsessKey == "undefined")
{
localrc = 1;
localmsg = "Session Key not retrieved";
}
}
}).on('end', function()
{
callback(localrc, localmsg, localsessKey, data);
}).on('close', function()
{
callback(localrc, localmsg, localsessKey, data);
}).on('error', function(err)
{
localrc = response.statusCode;
localmsg = err;
callback(localrc, localmsg, localsessKey, data);
});
connection:{
secureOptions: constants.SSL_OP_NO_TLSv1_2,
ciphers:'ECDHE-RSA-AES256-SHA:AES256-SHA:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM',
honorCipherOrder: true
},
when trying to use the client with GET and SSL, using the above, constants <--- is not defined.
The REST API server returns uncompressed JSON to my node-rest-client which fails to capture and return that JSON data since compression support was added.
My app works fine again if I replace the line if(!encoding || /^\s*$/.test(encoding)){
by if(1)
. Running with DEBUG shows that encoding= UTF-8
. Also the second expression after the ||
evaluates to false
.
Still trying to understand what /^\s*$/.test(encoding)
is supposed to do, in order to eventually propose a patch. Any hints? Thanks.
When I try to GET
certain URLs, I receive the following error:
Error: Parse Error
at Socket.socketOnData (http.js:1583:20)
at TCP.onread (net.js:527:27)
This happens reproducibly when for instance loading Amazon pages:
var rest = new (require('node-rest-client')).Client();
rest.get('http://www.amazon.com/kids-toys-action-figures-accessories/b?ie=UTF8&node=165993011', function (err, response) {
if (response.statusCode != 200) throw new Error("Response: #{response.statusCode}");
console.log('done.');
}).on('error', function (err) {
console.error(err.stack);
});
I could not find anything unusual in the response from the server:
$ curl -X GET -I 'http://www.amazon.com/kids-toys-action-figures-accessories/b?ie=UTF8&node=165993011'
HTTP/1.1 200 OK
Date: Wed, 08 Oct 2014 11:43:15 GMT
Server: Server
x-amz-id-1: 0PX51KDS197ANZRNQCY9
x-amz-id-2: to2jzdxj+C8EUuRJgeEvCrdlThmPkzqiGsxQO1UeLx7VJzEndp280sQmfoIH48M0NsMbA7vGUR8=
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
Vary: Accept-Encoding,User-Agent
Transfer-Encoding: chunked
Is there anything I can do?
When calling a resourceURL that is NOT XML nor JSON, but HTML, the client breaks with the following message:
{
code: "InternalError",
message: "Unexpected token <"
}
I believe this is because the server is trying to parse an HTML page at the time of the request... I can't see the HTTP Response header and I can't guarantee there were any of the application/json or application/xml, but the fact is that I can't quietly handle this error using the "on('error'"....
self.client.get(resourceUrl, function(responseBody, response) {
deferred.resolve(JSON.parse(responseBody));
}).on('error',function(err){
console.log('something went wrong on the request' + err, err.request.options);
deferred.resolve({status: "ERROR", message: err});
});
Shouldn't the data be returned to the client API in Strings, instead of trying to parse the content? That way, the user can also verify the content type of the response, as it is never guaranteed that the server is serving the content...
Any suggestions for workarounds? My package.json declares the latest version:
"node-rest-client": "^0.8.3",
Thanks
Marcello
To include the needs for the content-type header in POST requests. Please see:
#6
Thanks.
https://github.com/aacerox/node-rest-client/blob/master/lib/node-rest-client.js#L396
This line seems to always call toString()
on the Buffer response from the server. My understanding is that this will interpret the data as UTF-8 and thus corrupt binary data.
I believe gzipped data from the server may avoid this problem. Is there some way to download non-gzipped binary data using node-rest-client?
TypeError: Cannot read property 'tunnel' of undefined
In order to make that code to work:
var sys = require('util');
var Client = require('node-rest-client').Client;
var client = new Client();
var args ={
path:{"lat":-31.32622,"lon":-64.241352}
};
client.get("https://search.twitter.com/search.json?geocode=${lat},${lon},1mi", args,
function(data, response){
console.log(data.completed_in);
//console.log(response);
}
);
I needed to change that line in the library:
Change:
}else if (self.isJSON(content)){
debug("typeof data es ", typeof data);
callback(JSON.parse(data), res);
}else{
callback(data, res);
}
By:
}else if (self.isJSON(content)){
debug("typeof data es ", typeof data);
callback(JSON.parse(data), res);
}else{
callback(JSON.parse(data), res);
}
Hi,
creating a simple REST-Service with express and using this lib I encountered the problem, that the result is not parsed as JSON although one is returned and the content type was set.
Currently the code checks for
"jsonctype":["application/json","application/json;charset=utf-8"]
but express created application/json; charset=utf-8
, simply adding a third element in the list is helping in that case or changing the detection with a split and comparing each element after having trimmed it.
If you wish I can drop a PR later, depending which solution you prefer or maybe you have another one in mind.
Kind regards,
Michael
Maybe I am doing something stupid, but it looks like the data is not even parsed:
var Client = require('node-rest-client').Client;
client = new Client();
client.get('http://localhost:5050/workbooks/TotalDailyGrossRevenue/last-refresh-time', function(data, response){
console.log('Data is a', typeof data);
});
Results in:
$ node scripts/test_client.js
Data is a string
Curling looks fine:
$ curl -v http://localhost:5050/workbooks/TotalDailyGrossRevenue/last-refresh-time
* About to connect() to localhost port 5050 (#0)
* Trying ::1...
* Connection refused
* Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 5050 (#0)
> GET /workbooks/TotalDailyGrossRevenue/last-refresh-time HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8y zlib/1.2.5
> Host: localhost:5050
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 555
< ETag: "1044588208"
< Date: Wed, 19 Feb 2014 19:40:37 GMT
< Connection: keep-alive
<
{
"id": "TotalDailyGrossRevenue",
"worksheets": [
{
"name": "2013 Goal Tracking Data"
},
{
"name": "2013 Goal Tracking Graph"
},
{
"name": "Best Day"
},
{
"name": "By Product"
},
{
"name": "Data Table"
},
{
"name": "Total"
},
{
"name": "2013 Revenue Goal Tracker"
},
{
"name": "Data"
},
{
"name": "Gross Revenue by Product"
},
{
"name": "Total Gross Revenue"
}
],
"lastRefresh": "2014-02-19T18:49:45.085Z"
* Connection #0 to host localhost left intact
}* Closing connection #0
var docs = function (app) {
var container;
var Client = require('node-rest-client').Client;
client = new Client();
// handling request error events
client.get("http://VM-MOSS01-TEST.cco.cco-cce.org:80/operations/NOPA/_vti_bin/listdata.svc/Certifications?$select=Certification,CertDescription,Id", function(data, response){
// parsed response body as js object
console.log(data);
container = data;
// raw response
console.log(response);
}).on('error',function(err){
//console.log('something went wrong on the request', err.request.options)
console.dir(err);
});
/*
app.get('/api/docs', function (req, res) {
res.json(container);
});
};
module.exports = docs;
on "error" Ouput
{ [Error: read ECONNRESET]
code: 'ECONNRESET',
errno: 'ECONNRESET',
syscall: 'read',
request:
{ domain: null,
_events: { error: [Function] },
_maxListeners: 10,
options:
{ host: 'vm-moss01-test",
port: '80',
path: '/operations/NOPA/_vti_bin/listdata.svc/Certifications?$select=Certification,CertDescription,Id',
method: 'GET' } } }
Any suggestions on how to troubleshoot this?
Non-tunneled proxy requests do not always lead to a successful response.
I have narrowed the issue down to the absence of a host
header in the request.
It appears there is support for the host
header, and it is initially filled correctly. Later on it gets deleted from the options though, leaving the request without the header entirely.
Your lib is really great. However, when using larger texts using Japanese characters, sometimes character corruption takes place. I made a pull-request a couple of days ago. It would be really great if you could have a look at it.
When response is chunked, node-rest-client internally calls Buffer.concat
, which expects a list of Buffer
s, not strings. Currently chunks are strings which triggers mentioned error. I'll provide fix in a moment. See also: feross/buffer#47
When using node-rest-client with the PushBullet API (just as a test), the http basic auth headers are not properly passed to the server.
var restClient = require('node-rest-client').Client;
var accessToken = "<access code here>";
var auth = { user: accessToken, password: "" };
var rest = new restClient(auth);
var getAvailableDevices = function(callback)
{
var url = "https://api.pushbullet.com/v2/devices";
rest.get(url, function(data, response)
{
//response gives "Access token is missing or invalid." error
});
}
The access token is tested and valid with a curl request
Please advise
I'm using node-rest-client for my project and I've come to the point where I want to start unit testing my classes that utilize node-rest-client. Is there any examples on how I can mock the Client in my tests? For example, my class might look like this:
SomeClass.prototype.execute = function(orderId)
{
var deferred = q.defer();
var self = this;
this.client.get(endpoint + '/orders/' + orderId, args, function(responseData, response)
{
if (response.statusCode === 200)
{
deferred.resolve(responseData);
}
else
{
deferred.reject(new Error('Error occurred'));
}
})
.on('error', function(error)
{
deferred.reject(new Error('Error occurred'));
});
return deferred.promise;
};
this.client
is a Client instance, and I'm using q for promises.
How can I easily mock the clinet so I reach the three scenarios? The three scenarios are:
Requests that do not contain a Content-Encoding header are not working in the latest version of the library. At line 313 indexOf is called on an undefined variable causing the response handling code to fail.
On of the services my app relies upon suddenly changed the mime type to application/json;odata=verbose;charset=utf-8
(probably some redmondish attempt to screw up something not invented by them).
As a result the body of the message is not interpreted as JSON anymore. So we should either match this obscure mimetype, or match on a substring.
Would be great to support Promise interface and use client this way:
client.get("/foo").then(...);
If I use the HTTPS client built into node library, I can pass "rejectUnauthorized" to false and node will happily make https request to server with self signed certificate. How can I do this with node-rest-client? I could not see this in the source code.
There is no way to create a simple Client without Proxy.
Seems to be caused by one of the last commits. Error:
TypeError: Cannot read property 'tunnel' of undefined
at new exports.Client (C:\nodejs\node_modules\node-rest-client\lib\node-rest-client.js:14:42)
at Object. (C:\nodejs\testapp\restclient.js:3:14)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3
Hi,
I´m a begginer and i think i have a basic doubt:
When i run the following code in the internet explorer:
http://route.st.nlp.nokia.com/routing/6.2/calculateisoline.json?mode=fastest%3Bcar%3Btraffic%3Adisabled&start=19.419426%2C+-99.217170&time=PT0H01M&app_id=DemoAppId01082013GAL&app_code=AJKnXv84fjrb0KIHawS0Tg
The response is a file in json with the information i need of latitude and longitude points
But when i execute mi node.js application with node-rest-client the only thing i get is the following:
C:>node here.js
{ Response:
{ isolines: [ [Object] ],
MetaInfo:
{ Timestamp: '2014-06-25T23:55:14.472Z',
AdditionalData: [Object] },
Center: { Latitude: 19.4191952, Longitude: -99.2172394 } } }
Why in the isoline part only says [[Object]] and i cant see the same points of the first json file.
Thanks a lot!
This is a warning that an EventEmitter instance has more than the configured listeners set. By default that's 10 with node.
I have some client wrapper classes that call node-rest-client. One in particular is an authentication client.
The "core" services I access through REST all call the auth client first. Given that there are multiple core service calls per module functionality, the auth client can get called more than 10x while serving a user request, each going further down the promise chain. This means that node-rest-client can ultimately be invoked many times before everything unwinds.
I'm pretty sure the Event Emitter warning (and associated stack trace shown below) occurs in node-rest-client but can't figure out how to increase its event emitter listener configuration.
Trace
at Object.addListener (events.js:179:15)
at new exports.Client (E:\src\clients\client1\ztarmobile\rest\node_modules\node-rest-client\lib\node-rest-client.js:326:17)
at RestClientBase.rest (E:\src\clients\client1\ztarmobile\rest\server\components\rest-client\RestClientBase.js:154:30)
at RestClientBase.AuthClient.authorizeResource (E:\src\clients\client1\ztarmobile\rest\server\components\rest-client\AuthClient.js:52:21)
at Object.module.exports.authorizeProductCatalogEntry (E:\src\clients\client1\ztarmobile\rest\server\components\service\authorize.service.js:14:27)
at E:\src\clients\client1\ztarmobile\rest\server\components\service\authorize.service.js:45:47
at _fulfilled (e:\src\clients\client1\components\node_modules\q\q.js:794:54)
at self.promiseDispatch.done (e:\src\clients\client1\components\node_modules\q\q.js:823:30)
at Promise.promise.promiseDispatch (e:\src\clients\client1\components\node_modules\q\q.js:756:13)
at e:\src\clients\client1\components\node_modules\q\q.js:564:44
/root/razvan/bc-olympia/node_modules/node-rest-client/lib/node-rest-client.js:14
self.useProxyTunnel = self.options.proxy.tunnel===undefined?true:self.options
^
TypeError: Cannot read property 'tunnel' of undefined
at new exports.Client (/root/razvan/bc-olympia/node_modules/node-rest-client/lib/node-rest-client.js:14:42)
at Object.module.exports.generateService (/root/razvan/bc-olympia/services/player-server.js:4:18)
at Object.<anonymous> (/root/razvan/bc-olympia/server.js:34:58)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
It seems like the last commit broke something
We have modified this part of your code (node-rest-client.js):
296 "isJSON":function(content){
297 content = content.replace(' ', '');
because our restful server replies with a space between chars ';' and 'charset ....':
"application/json; charset=utf-8"
but your code expects:
"application/json;charset=utf-8"
In general your code does not support spaces in the 'Content-Type' response header.
Hi
I'm having trouble getting POST methods to work - the request arrives at my API, but the req.body element is an empty object (even though I have specified args.data). GET works fine.
I tried with both direct and registered methods.
My API is implemented using express and is currently running on localhost:5000. The API works if I use an HTML form to post...
Any ideas what I might be missing?
Thanks,
Toby
for(var i=0; i <50; i++)
{
var client = new Client();
var args = {
data: data,
headers:{"Content-Type": "application/json"}
};
client.post("http://parkloco.com:9999/park", args, function(data,response) {
// parsed response body as js object
console.log(response);
});
}
The connection is reset by the node app. In unirest node api, it works perfectly fine!
When getting a 500 or 502 from an API request, the callback is invoked instead of the error handler. What type of incidents are actually meant to invoke the error handler, if not these are? Am I missing something here?
My code just follows the examples from README:
var req = client.get(url, args, function(data,response) {
// response.statusCode == 500
// Shouldn't the error handler below deal with this?
});
req.on('error', function(err) {
logger.error("Request failed", err);
})
To perform JSON parsing of response, the code checks of "jsonctype":["application/json","application/json;charset=utf-8"], in response header.
Its failing for me becuase in my case. the rest endpoint returns content header as "application/json; charset=utf-8" (notice the space between encoding directive).
May be the better approach would be to split the string and look for "application/json"
In case if you subscribe on error event:
client.on('error',function(err){
console.error('Something went wrong', err);
});
It's unfortunately impossible to match which request generated this error. It'd be really helpful when you need to react somehow inside this request and invoke error callback to its originator.
Any idea how to make it work?
May be it makes sence to implement some error callback inside get(), post() etc. functions to catch the error?
Looks like this project checks if there is any value for process.env.DEBUG, which causes a lot of clutter when trying to debug other parts of the app unrelated to this project.
It would be awesome if you guys could use node debug or check for the a namespaced value instead of just existance in a fashion similar to node debug so it is easier to get fine grained debug statments.
Please, look at the screenshot with problem:
https://s3.amazonaws.com/donnicky_screenshots/2014-09-22_01-16.png
Hi there,
I'm looking for some guidance on how to handle compressed responses.
Can you provide an example on how to gunzip the response data?
Thanks in advance
Tim
It doesn't look like it is possible to set rejectUnauthorized in the options. This would definitely be helpful.
Hi,
I am trying to replicate the example in your Readme file but with no success.
This is my JS code:
function callAPI(){
var client = require('node-rest-client').Client;
// direct way
var client = new exports.Client();
client.post("http://127.0.0.1:8081/daqvalidator/validate?type=m", function(data, response){
// parsed response body as js object
console.log(data);
// raw response
console.log(response);
});
// registering remote methods
client.registerMethod("xmlMethod", "http://127.0.0.1:8081/daqvalidator/validate", "POST");
client.methods.xmlMethod(args,function(data,response){
// parsed response body as js object
console.log(data);
// raw response
console.log(response);
});
}
When trying to call the function, I get the following error:
Uncaught Error: Module name "node-rest-client" has not been loaded yet for context: _. Use require([]) http://requirejs.org/docs/errors.html#notloaded
Would you have any idea why this could be happening?
Best Regards,
Jeremy
I had node-rest-client included in my dependencies as latest version, and when I 'npm install'ed today, all of my test cases for one of my projects broke. I started getting errors with a call to .toLowerCase, which actually turned out to be within the node-rest-client isXML function.
As it turns out, not all of my requests to a Restify API actually respond with a content type, because not all of the responses actually have content. When there is no content in a response, the following line 285 in node-rest-client.js in v0.8.8 fails:
result = this.xmlctype[i].toLowerCase() === content.toLowerCase();
I reverted back to v0.8.6, which has this code instead:
result = this.xmlctype[i] === content;
That code works, since it is not trying to call .toLowerCase() on an undefined object. I figure just checking if (content)
first, before assigning the result, would clear the issue up.
Hi,
I have experienced an error throwing from Socket.socketOnData method when calling REST client behind a proxy. Here is the code I used:
var RestClient = require('node-rest-client').Client,
client = new RestClient({
proxy:{
host:"proxyDomain",
port: 8080,
user:"username",
password:"password"
}
});
client.registerMethod("jsonMethod", "http://ogcef.one.gov.hk/event-psi/json/calendar/20140215.json", "GET");
client.methods.jsonMethod(function (data, response) {...});
After checking up the REST client code a bit, I found that it will try to connect to proxy via 'CONNECT' method using Node.js http client and then making another connection after this call returned successfully. The issue is that if you use Node.js http client to trigger a call using 'CONNECT' method, the above exception is thrown.
May I suggest to use something similiar below so that REST client can connect to the target URL successfully behind a proxy environment? I have tested in my local and it works:
var request = http.request({
host: 'proxy',
port: '8080',
method: 'GET',
path: 'http://ogcef.one.gov.hk/event-psi/json/calendar/20140215.json',
headers: {
'host': 'ogcef.one.gov.hk',
'Proxy-Authentication': 'Basic ' + new Buffer(['username','password'].join(":")).toString("base64")
},
agent: false
});
Is it possible to change ConnectManager.proxy function to use the approach above instead of making a CONNECT call?
Thanks and this package is an awesome package for Node.js :)
Sincerely,
Jason
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.