Skip to content

Commit

Permalink
allow request id to be set. remove reqIdHeaders option (#1256)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonutEspresso committed Dec 22, 2016
1 parent e01b7a3 commit 4fba68c
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 129 deletions.
10 changes: 7 additions & 3 deletions docs/pages/components/request.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -119,12 +119,16 @@ server.get('/:x/bar', function(req, res, next) {
``` ```




## id() ## id([reqId])

* `[reqId]` {String}


__Returns__ {String} __Returns__ {String}


Returns the request id. If a request id header was not specified for incoming Returns the request id. If a `reqId` value is passed in, this will
requests, this will return a UUID. become the request's new id. The request id is immutable, and can only be
set once. Attempting to set the request id more than once will cause
restify to throw.




## path() ## path()
Expand Down
1 change: 0 additions & 1 deletion docs/pages/components/server.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ The `createServer()` method takes the following options:
|version|String|Array|A default version to set for all routes| |version|String|Array|A default version to set for all routes|
|handleUpgrades|Boolean|Hook the `upgrade` event from the node HTTP server, pushing `Connection: Upgrade` requests through the regular request handling chain; defaults to `false`| |handleUpgrades|Boolean|Hook the `upgrade` event from the node HTTP server, pushing `Connection: Upgrade` requests through the regular request handling chain; defaults to `false`|
|httpsServerOptions|Object|Any options accepted by [node-https Server](http://nodejs.org/api/https.html#https_https). If provided the following restify server options will be ignored: spdy, ca, certificate, key, passphrase, rejectUnauthorized, requestCert and ciphers; however these can all be specified on httpsServerOptions.| |httpsServerOptions|Object|Any options accepted by [node-https Server](http://nodejs.org/api/https.html#https_https). If provided the following restify server options will be ignored: spdy, ca, certificate, key, passphrase, rejectUnauthorized, requestCert and ciphers; however these can all be specified on httpsServerOptions.|
|reqIdHeaders|Array|an optional array of request id header names that will be used to set the request id (i.e., the value for req.getId())|
|strictRouting|Boolean|(Default=`false`). If set, Restify will treat "/foo" and "/foo/" as different paths.| |strictRouting|Boolean|(Default=`false`). If set, Restify will treat "/foo" and "/foo/" as different paths.|




Expand Down
18 changes: 17 additions & 1 deletion lib/request.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Request.prototype.href = Request.prototype.getHref;
* @returns {String} * @returns {String}
*/ */
Request.prototype.getId = function getId() { Request.prototype.getId = function getId() {

if (this._id !== undefined) { if (this._id !== undefined) {
return (this._id); return (this._id);
} }
Expand All @@ -226,7 +227,22 @@ Request.prototype.getId = function getId() {


return (this._id); return (this._id);
}; };
Request.prototype.id = Request.prototype.getId; Request.prototype.id = function id(reqId) {

var self = this;

if (reqId) {
if (self._id) {
throw new Error('request id is immutable, cannot be set again!');
} else {
assert.string(reqId, 'reqId');
self._id = reqId;
return self._id;
}
}

return self.getId();
};




/** /**
Expand Down
21 changes: 0 additions & 21 deletions lib/server.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -248,15 +248,12 @@ function optionsError(err, req, res) {
* @public * @public
* @class * @class
* @param {Object} options an options object * @param {Object} options an options object
* @param {Array} [options.reqIdHeaders] an array of request id headers to
* re-use from incoming requests
*/ */
function Server(options) { function Server(options) {
assert.object(options, 'options'); assert.object(options, 'options');
assert.object(options.log, 'options.log'); assert.object(options.log, 'options.log');
assert.object(options.router, 'options.router'); assert.object(options.router, 'options.router');
assert.string(options.name, 'options.name'); assert.string(options.name, 'options.name');
assert.optionalArrayOfString(options.reqIdHeaders, 'options.reqIdHeaders');


var self = this; var self = this;


Expand All @@ -274,11 +271,6 @@ function Server(options) {
this.socketio = options.socketio || false; this.socketio = options.socketio || false;
this._unfinishedRequests = 0; this._unfinishedRequests = 0;


var defaultReqIdHeaders = ['request-id', 'x-request-id'];
this.reqIdHeaders = (options.reqIdHeaders) ?
options.reqIdHeaders.concat(defaultReqIdHeaders) :
defaultReqIdHeaders;

var fmt = mergeFormatters(options.formatters); var fmt = mergeFormatters(options.formatters);
this.acceptable = fmt.acceptable; this.acceptable = fmt.acceptable;
this.formatters = fmt.formatters; this.formatters = fmt.formatters;
Expand Down Expand Up @@ -1123,19 +1115,6 @@ Server.prototype._setupRequest = function _setupRequest(req, res) {
res.header('Server', self.name); res.header('Server', self.name);
} }
res.version = self.router.versions[self.router.versions.length - 1]; res.version = self.router.versions[self.router.versions.length - 1];

// GH-1086: set request id based on array of headers, lowest index
// is highest priority.
var i = 0;

for (i = 0; i < self.reqIdHeaders.length; i++) {
var idName = self.reqIdHeaders[i];

if (req.headers.hasOwnProperty(idName) && req.headers[idName]) {
req._id = req.headers[idName];
break;
}
}
}; };




Expand Down
80 changes: 80 additions & 0 deletions test/request.test.js
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'; 'use strict';


var restifyClients = require('restify-clients'); var restifyClients = require('restify-clients');
var validator = require('validator');


var restify = require('../lib'); var restify = require('../lib');


Expand Down Expand Up @@ -90,3 +91,82 @@ test('query should return raw query string string', function (t) {
}); });
}); });



test('should generate request id on first req.id() call', function (t) {

SERVER.get('/ping', function (req, res, next) {
t.equal(typeof req.id(), 'string');
t.equal(validator.isUUID(req.id(), 4), true);
res.send();
return next();
});

CLIENT.get('/ping', function (err, _, res) {
t.ifError(err);
t.equal(res.statusCode, 200);
t.end();
});
});


test('should set request id', function (t) {

SERVER.pre(function setId(req, res, next) {
var newId = req.id('lagavulin');
t.equal(newId, 'lagavulin');
return next();
});

SERVER.get('/ping', function (req, res, next) {
t.equal(typeof req.id(), 'string');
t.equal(req.id(), 'lagavulin');
res.send();
return next();
});

CLIENT.get('/ping', function (err, _, res) {
t.ifError(err);
t.equal(res.statusCode, 200);
t.end();
});
});


test('should throw when setting request id after autogeneration', function (t) {

SERVER.get('/ping', function (req, res, next) {
t.equal(typeof req.id(), 'string');
t.equal(validator.isUUID(req.id(), 4), true);
t.throws(function () {
req.id('blowup');
}, Error, 'request id is immutable, cannot be set again!');
res.send();
return next();
});

CLIENT.get('/ping', function (err, _, res) {
t.ifError(err);
t.equal(res.statusCode, 200);
t.end();
});
});


test('should throw when setting request id twice', function (t) {

SERVER.get('/ping', function (req, res, next) {
req.id('lagavulin');
t.throws(function () {
req.id('blowup');
}, Error, 'request id is immutable, cannot be set again!');
res.send();
return next();
});

CLIENT.get('/ping', function (err, _, res) {
t.ifError(err);
t.equal(res.statusCode, 200);
t.end();
});
});

104 changes: 1 addition & 103 deletions test/server.test.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ var filed = require('filed');
var plugins = require('restify-plugins'); var plugins = require('restify-plugins');
var restifyClients = require('restify-clients'); var restifyClients = require('restify-clients');
var uuid = require('uuid'); var uuid = require('uuid');
var validator = require('validator');


var RestError = errors.RestError; var RestError = errors.RestError;
var restify = require('../lib'); var restify = require('../lib');
Expand Down Expand Up @@ -44,8 +43,7 @@ before(function (cb) {
dtrace: helper.dtrace, dtrace: helper.dtrace,
handleUncaughtExceptions: true, handleUncaughtExceptions: true,
log: helper.getLog('server'), log: helper.getLog('server'),
version: ['2.0.0', '0.5.4', '1.4.3'], version: ['2.0.0', '0.5.4', '1.4.3']
reqIdHeaders: ['x-req-id-a', 'x-req-id-b']
}); });
SERVER.listen(PORT, '127.0.0.1', function () { SERVER.listen(PORT, '127.0.0.1', function () {
PORT = SERVER.address().port; PORT = SERVER.address().port;
Expand Down Expand Up @@ -2263,106 +2261,6 @@ test('calling next(false) should early exit from pre handlers', function (t) {
}); });




test('GH-1086: should reuse request id when available', function (t) {

SERVER.get('/1', function (req, res, next) {
// the 12345 value is set when the client is created.
t.ok(req.headers.hasOwnProperty('x-req-id-a'));
t.equal(req.getId(), req.headers['x-req-id-a']);
res.send('hello world');
return next();
});

// create new client since we new specific headers
CLIENT = restifyClients.createJsonClient({
url: 'http://127.0.0.1:' + PORT,
headers:{
'x-req-id-a': 12345
}
});

CLIENT.get('/1', function (err, req, res, data) {
t.ifError(err);
t.equal(data, 'hello world');
t.end();
});
});


test('GH-1086: should use second request id when available', function (t) {

SERVER.get('/1', function (req, res, next) {
t.ok(req.headers.hasOwnProperty('x-req-id-b'));
t.equal(req.getId(), req.headers['x-req-id-b']);
res.send('hello world');
return next();
});

// create new client since we new specific headers
CLIENT = restifyClients.createJsonClient({
url: 'http://127.0.0.1:' + PORT,
headers:{
'x-req-id-b': 678910
}
});

CLIENT.get('/1', function (err, req, res, data) {
t.ifError(err);
t.equal(data, 'hello world');
t.end();
});
});


test('GH-1086: should use default uuid request id if none provided',
function (t) {

SERVER.get('/1', function (req, res, next) {
t.ok(req.getId());
t.ok(validator.isUUID(req.getId()));
res.send('hello world');
return next();
});

// create new client since we new specific headers
CLIENT = restifyClients.createJsonClient({
url: 'http://127.0.0.1:' + PORT
});

CLIENT.get('/1', function (err, req, res, data) {
t.ifError(err);
t.equal(data, 'hello world');
t.end();
});
});


test('GH-1086: empty request id should be ignored', function (t) {

SERVER.get('/1', function (req, res, next) {
t.ok(req.headers.hasOwnProperty('x-req-id-b'));
t.equal(req.getId(), req.headers['x-req-id-b']);
res.send('hello world');
return next();
});

// create new client since we new specific headers
CLIENT = restifyClients.createJsonClient({
url: 'http://127.0.0.1:' + PORT,
headers:{
'x-req-id-a': '',
'x-req-id-b': 12345
}
});

CLIENT.get('/1', function (err, req, res, data) {
t.ifError(err);
t.equal(data, 'hello world');
t.end();
});
});


test('GH-1078: server name should default to restify', function (t) { test('GH-1078: server name should default to restify', function (t) {


var myServer = restify.createServer(); var myServer = restify.createServer();
Expand Down

0 comments on commit 4fba68c

Please sign in to comment.