Skip to content

Commit f696bd6

Browse files
committed
fix some issues
new custom method, and follow redirects
1 parent 93a835f commit f696bd6

File tree

4 files changed

+82
-47
lines changed

4 files changed

+82
-47
lines changed

lib/node-rest-client.js

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
var http = require('http'),
2-
https = require('https'),
1+
var http = require('follow-redirects').http,
2+
https = require('follow-redirects').https,
33
parseString = require('xml2js').parseString,
44
urlParser = require('url'),
55
util = require("util"),
@@ -10,14 +10,19 @@ var http = require('http'),
1010
exports.Client = function (options){
1111
var self = this;
1212
var connectManager = new ConnectManager();
13+
//declare util constants
14+
var CONSTANTS={
15+
HEADER_CONTENT_LENGTH:"Content-Length"
16+
};
17+
1318

1419
self.options = options || {},
1520
self.useProxy = (self.options.proxy || false)?true:false,
1621
self.useProxyTunnel = (!self.useProxy || self.options.proxy.tunnel===undefined)?false:self.options.proxy.tunnel,
1722
self.proxy = self.options.proxy,
1823
self.connection = self.options.connection || {},
19-
self.mimetypes = self.options.mimetypes || {};
20-
self.requestConfig = self.options.requestConfig || {};
24+
self.mimetypes = self.options.mimetypes || {},
25+
self.requestConfig = self.options.requestConfig || {},
2126
self.responseConfig = self.options.responseConfig || {};
2227

2328
this.methods={};
@@ -42,8 +47,9 @@ exports.Client = function (options){
4247
this._httpRequest = req;
4348
};
4449

45-
var Util = {
4650

51+
52+
var Util = {
4753
createProxyPath:function(url){
4854
var result = url.host;
4955
// check url protocol to set path in request options
@@ -78,7 +84,8 @@ exports.Client = function (options){
7884
host: url.host.indexOf(":") == -1?url.host:url.host.substring(0,url.host.indexOf(":")),
7985
port: url.port === undefined?defaultPort:url.port,
8086
path: url.path,
81-
protocol:protocol
87+
protocol:protocol,
88+
href:url.href
8289
};
8390

8491
if (self.useProxy) result.agent = false; // cannot use default agent in proxy mode
@@ -88,7 +95,7 @@ exports.Client = function (options){
8895

8996
} else if (self.options.user && !self.options.password){
9097
// some sites only needs user with no password to authenticate
91-
result.auth = self.options.user;
98+
result.auth = self.options.user + ":";
9299
}
93100

94101

@@ -201,6 +208,7 @@ exports.Client = function (options){
201208
var options = this.createConnectOptions(this.parsePathParameters(args,url), method);
202209
debug("options pre connect",options);
203210
options.method = method,
211+
clientRequest.href=options.href,
204212
options.clientRequest = clientRequest,
205213
options.headers= options.headers || {};
206214

@@ -211,7 +219,7 @@ exports.Client = function (options){
211219
callback = args;
212220
//add Content-length to POST/PUT/DELETE/PATCH methods
213221
if (method === 'POST' || method === 'PUT' || method === 'DELETE' || method === 'PATCH'){
214-
options.headers['Content-Length'] = 0;
222+
options.headers[CONSTANTS.HEADER_CONTENT_LENGTH] = 0;
215223
}
216224
} else if (typeof args === 'object') {
217225
// add headers and POST/PUT/DELETE/PATCH data to connect options to be passed
@@ -225,13 +233,13 @@ exports.Client = function (options){
225233

226234
}
227235

228-
//always set Content-length header
229-
//set Content lentgh for some servers to work (nginx, apache)
230-
if (args.data !== undefined){
236+
//always set Content-length header if not set previously
237+
//set Content lentgh for some servers to work (nginx, apache)
238+
if (args.data !== undefined && !options.headers.hasOwnProperty(CONSTANTS.HEADER_CONTENT_LENGTH)){
231239
options.data = args.data;
232-
options.headers['Content-Length'] = Buffer.byteLength((typeof args.data === 'string' ? args.data:JSON.stringify(args.data)), 'utf8');
240+
options.headers[CONSTANTS.HEADER_CONTENT_LENGTH] = Buffer.byteLength((typeof args.data === 'string' ? args.data:JSON.stringify(args.data)), 'utf8');
233241
}else{
234-
options.headers['Content-Length'] = 0;
242+
options.headers[CONSTANTS.HEADER_CONTENT_LENGTH] = 0;
235243
}
236244
// we have args, go and check if we have parameters
237245
if (args.parameters && Object.keys(args.parameters).length > 0){
@@ -265,6 +273,13 @@ exports.Client = function (options){
265273
connectManager.xmlctype = mimetypes.xml;
266274
}
267275
}
276+
},
277+
createHttpMethod:function(methodName){
278+
return function(url, args, callback){
279+
var clientRequest = new ClientRequest();
280+
Util.connect(methodName.toUpperCase(), url, args, callback, clientRequest);
281+
return clientRequest;
282+
};
268283
}
269284
},
270285
Method = function(url, method){
@@ -294,35 +309,15 @@ exports.Client = function (options){
294309

295310

296311

297-
this.get = function(url, args, callback){
298-
var clientRequest = new ClientRequest();
299-
Util.connect('GET', url, args, callback, clientRequest);
300-
return clientRequest;
301-
};
302-
303-
this.post = function(url, args, callback){
304-
var clientRequest = new ClientRequest();
305-
Util.connect('POST', url, args, callback, clientRequest);
306-
return clientRequest;
307-
};
312+
this.get = Util.createHttpMethod("get");
308313

309-
this.put = function(url, args, callback){
310-
var clientRequest = new ClientRequest();
311-
Util.connect('PUT', url, args, callback, clientRequest);
312-
return clientRequest;
313-
};
314+
this.post = Util.createHttpMethod("post");
315+
316+
this.put = Util.createHttpMethod("put");
314317

315-
this.delete = function(url, args, callback){
316-
var clientRequest = new ClientRequest();
317-
Util.connect('DELETE', url, args, callback, clientRequest);
318-
return clientRequest;
319-
};
318+
this.delete = Util.createHttpMethod("delete");
320319

321-
this.patch = function(url, args, callback){
322-
var clientRequest = new ClientRequest();
323-
Util.connect('PATCH', url, args, callback, clientRequest);
324-
return clientRequest;
325-
};
320+
this.patch = Util.createHttpMethod("patch");
326321

327322

328323
this.registerMethod = function(name, url, method){
@@ -335,6 +330,10 @@ exports.Client = function (options){
335330
delete this.methods[name];
336331
};
337332

333+
this.addCustomHttpMethod=function(methodName){
334+
self[methodName.toLowerCase()] = Util.createHttpMethod(methodName);
335+
}
336+
338337
// handle ConnectManager events
339338
connectManager.on('error',function(err){
340339
self.emit('error',err);
@@ -348,14 +347,14 @@ exports.Client = function (options){
348347

349348

350349
var ConnectManager = function() {
351-
this.xmlctype = ["application/xml","application/xml;charset=utf-8"];
350+
this.xmlctype = ["application/xml","application/xml;charset=utf-8","text/xml","text/xml;charset=utf-8"];
352351
this.jsonctype = ["application/json","application/json;charset=utf-8"],
353352
this.isXML = function(content){
354353
var result = false;
355354
if (!content) return result;
356355

357356
for (var i=0; i<this.xmlctype.length;i++){
358-
result = this.xmlctype[i].toLowerCase() === content.toLowerCase();
357+
result = this.xmlctype[i].trim().toLowerCase() === content.trim().toLowerCase();
359358
if (result) break;
360359
}
361360

@@ -366,7 +365,7 @@ exports.Client = function (options){
366365
if (!content) return result;
367366

368367
for (var i=0; i<this.jsonctype.length;i++){
369-
result = this.jsonctype[i].toLowerCase() === content.toLowerCase();
368+
result = this.jsonctype[i].trim().toLowerCase() === content.trim().toLowerCase();
370369
if (result) break;
371370
}
372371

@@ -426,13 +425,15 @@ exports.Client = function (options){
426425
this.handleResponse = function(res,data,callback){
427426
var content = res.headers["content-type"] && res.headers["content-type"].replace(/ /g, '');
428427

429-
debug("response content is ",content);
428+
debug("response content is [",content,"]");
430429
// XML data need to be parsed as JS object
431430
if (this.isXML(content)){
431+
debug("detected XML response");
432432
parseString(data.toString(), function (err, result) {
433433
callback(result, res);
434434
});
435435
}else if (this.isJSON(content)){
436+
debug("detected JSON response");
436437
var jsonData,
437438
data = data.toString();
438439
try {
@@ -447,6 +448,7 @@ exports.Client = function (options){
447448
}
448449
callback(jsonData, res);
449450
}else{
451+
debug("detected unknown response");
450452
callback(data, res);
451453
}
452454
},

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
"author": "Alejandro Alvarez Acero",
33
"name": "node-rest-client",
44
"description": "node API REST client",
5-
"version": "2.0.1",
5+
"version": "2.5.0",
66
"repository": {
77
"type":"git",
88
"url": "https://github.com/aacerox/node-rest-client.git"
99
},
1010
"main": "./lib/node-rest-client",
1111
"dependencies": {
1212
"xml2js":">=0.2.4",
13-
"debug": "~2.2.0"
13+
"debug": "~2.2.0",
14+
"follow-redirects":">=1.2.0"
1415
},
1516
"devDependencies": {
1617
"jasmine-node":">=1.2.3"

readme.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# REST Client for Node.js
2+
[![npm version](https://badge.fury.io/js/node-rest-client.svg)](https://www.npmjs.com/package/node-rest-client)
3+
[![Build Status](https://travis-ci.org/olalonde/node-rest-client.svg?branch=master)](https://travis-ci.org/olalonde/node-rest-client)
4+
5+
[![NPM](https://nodei.co/npm/node-rest-client.png?downloads=true)](https://nodei.co/npm/node-rest-client.png?downloads=true)
26

37
**NOTE:** _Since version 0.8.0 node does not contain node-waf anymore. The node-zlib package which node-rest-client make use of, depends on node-waf.Fortunately since version 0.8.0 zlib is a core dependency of node, so since version 1.0 of node-rest-client the explicit dependency to "zlib" has been removed from package.json. therefore if you are using a version below 0.8.0 of node please use a versión below 1.0.0 of "node-rest-client". _
48

@@ -7,12 +11,14 @@ Allows connecting to any API REST and get results as js Object. The client has t
711
- Transparent HTTP/HTTPS connection to remote API sites.
812
- Allows simple HTTP basic authentication.
913
- Allows most common HTTP operations: GET, POST, PUT, DELETE, PATCH.
14+
- Allows creation of custom HTTP Methods (PURGE, etc.)
1015
- Direct or through proxy connection to remote API sites.
1116
- Register remote API operations as client own methods, simplifying reuse.
1217
- Automatic parsing of XML and JSON response documents as js objects.
1318
- Dynamic path and query parameters and request headers.
1419
- Improved Error handling mechanism (client or specific request)
1520
- Added support for compressed responses: gzip and deflate
21+
- Added support for follow redirects thanks to great [follow-redirects](https://www.npmjs.com/package/follow-redirects) package
1622

1723

1824
## Installation
@@ -152,8 +158,6 @@ client.get("http://remote.site/rest/json/${id}/method?arg1=${arg1}&arg2=${arg2}"
152158
});
153159
```
154160

155-
156-
157161
### HTTP POST and PUT methods
158162

159163
To send data to remote site using POST or PUT methods, just add a data attribute to args object:
@@ -284,7 +288,23 @@ req.on('error', function (err) {
284288
console.log('request error', err);
285289
});
286290
```
291+
### Follows Redirect
292+
Node REST client follows redirects by default to a maximum of 21 redirects, but it's also possible to change follows redirect default config in each request done by the client
293+
```javascript
294+
var client = new Client();
287295

296+
// request and response additional configuration
297+
var args = {
298+
requestConfig: {
299+
followRedirects:true,//whether redirects should be followed(default,true)
300+
maxRedirects:10//set max redirects allowed (default:21)
301+
},
302+
responseConfig: {
303+
timeout: 1000 //response timeout
304+
}
305+
};
306+
307+
```
288308

289309
### Connect through proxy
290310

test/local-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var Client = require("../lib/node-rest-client.js").Client;
2+
var client = new Client();
3+
4+
console.log("client es ", client);
5+
/*
6+
client.get("http://localhost:8080/xml",(data,response) => console.log("DATA IS ", data));
7+
*/
8+
client.addCustomHttpMethod("purge");
9+
10+
var request = client.purge("http://localhost:8080/xml",(data,response) => console.log("DATA IS ", data) );
11+
12+
console.log("REQUEST is ", request);

0 commit comments

Comments
 (0)