Skip to content

Commit

Permalink
Merge pull request #32 from smollweide/develop
Browse files Browse the repository at this point in the history
v0.13.0
  • Loading branch information
smollweide authored Apr 21, 2017
2 parents ec62431 + abb8265 commit c948890
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 114 deletions.
13 changes: 13 additions & 0 deletions demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ mockServer({
'Global-Custom-Header': 'Global-Custom-Header',
},
customDTOToClassTemplate: __dirname + '/templates/dto_es6flow.ejs',
middleware: {
'/rest/products/#{productCode}/GET'(serverOptions, requestOptions) {
var productCode = requestOptions.req.params[0].split('/')[3];

if (productCode === '1234') {
requestOptions.res.statusCode = 201;
requestOptions.res.end('product 1234');
return null;
}

return 'success';
}
},
swaggerImport: {
protocol: 'http',
authUser: undefined,
Expand Down
20 changes: 20 additions & 0 deletions doc/readme-middleware.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Middleware

For validation and self controlled responses you can select middleware as response.
The middleware function will be called, in case of "middleware" is selected. It's response can be a string which will continue with the given string as selected response. If you return null or undefined you have to implement the response by yourself.

[example](/demo/index.js#L22)

## Parameter[0] serverOptions

See [node-mock-server options](/doc/readme-options.md)

## Parameter[1] responseOptions

| attribute | type | description |
| ------------- | ------------- | ----- |
| req | Object | The (request object)[http://expressjs.com/en/api.html#req]. |
| res | Object | The (response object)[http://expressjs.com/en/api.html#res]. |
| method | string | Contains a string corresponding to the HTTP method of the request: GET, POST, PUT, and so on. |
| dir | string | The directory of selected response |
| preferences | Object | The preferences object |
6 changes: 6 additions & 0 deletions doc/readme-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ Default value: `origin, x-requested-with, content-type`

A string that define the header "Access-Control-Allow-Headers".

#### options.middleware
Type: `Object`
Optional

A object including the middleware functions.
Read [middleware.md](/doc/readme-middleware.md) for details.

#### options.swaggerImport
Type: `Object`
Expand Down
3 changes: 3 additions & 0 deletions lib/UserInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ UserInterface.prototype = extend(UserInterface.prototype, {
}

var availableMockResponses = this.readDir(mockPath, ['response.txt', '.DS_Store']);
availableMockResponses.push({
file: 'middleware',
});
var availableMockResponsesOut = [];
var selected;
try {
Expand Down
163 changes: 109 additions & 54 deletions lib/controller/MockController.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,34 @@ MockController.prototype = extend(MockController.prototype, {
appController.app.all('/*', this._handleMockRequest.bind(this));
},

/**
* @method _acceptMiddleware
* @param {Object} serverOptions
* @param {Object} responseOptions
* @private
*/
_acceptMiddleware: function (serverOptions, responseOptions) {
var endPointId = responseOptions.dir.replace(serverOptions.dirName, '').replace(/\/$/, '');
var middleware = serverOptions.middleware;

if (!endPointId || !middleware || typeof middleware[endPointId] !== 'function') {
responseOptions.res.statusCode = 500;
responseOptions.res.end('Error: middleware for ' + endPointId + '" don\'t exist!');
return false;
}

return middleware[endPointId](serverOptions, responseOptions);
},

/**
* @method _handleMockRequest
* @param {object} req
* @param {object} res
* @param {Object} req
* @param {Object} res
* @private
*/
_handleMockRequest: function (req, res) {

var path = req.originalUrl.replace(this.options.urlPath, this.options.restPath);
var method = req.method;
var dir = this._findFolder(path, this.options) + '/' + method + '/';
var expectedResponse = this._getExpectedResponse(req, dir);
var preferences = this.getPreferences(this.options);
var timeout = 0;
var responseFilePath;
var responseHeadersFilePath;
var responseHeaders;
var headers = this.options.headers || {};
var options;
Expand All @@ -62,55 +74,42 @@ MockController.prototype = extend(MockController.prototype, {
return true;
}

if (preferences && preferences.responseDelay) {
timeout = parseInt(preferences.responseDelay, 10);
}
options = this.getResponseOptions(req, res);

responseFilePath = dir + 'mock/' + expectedResponse + '.json';
responseHeadersFilePath = dir + 'mock/' + expectedResponse + '.headers.json';
if (!options) {
return;
}

// Fallback to success.json
if (!this.existFile(responseFilePath)) {
expectedResponse = 'success';
responseFilePath = dir + 'mock/success.json';
this.writeFile(dir + 'mock/response.txt', 'success');
if (!this.existFile(options.responseFilePath)) {
options.expectedResponse = 'success';
options.responseFilePath = options.dir + 'mock/success.json';
this.writeFile(options.dir + 'mock/response.txt', 'success');
}

// Add response headers
if (this.existFile(responseHeadersFilePath)) {
responseHeaders = JSON.parse(this.readFile(responseHeadersFilePath)) || {};
if (this.existFile(options.responseHeadersFilePath)) {
responseHeaders = JSON.parse(this.readFile(options.responseHeadersFilePath)) || {};
}

options = {
req: req,
res: res,
path: path,
method: method,
dir: dir,
expectedResponse: expectedResponse,
preferences: preferences,
timeout: timeout,
responseFilePath: responseFilePath,
};

this._writeDefaultHeader(res, extend(headers, responseHeaders));

setTimeout(function () {
if (!this._hasValidDynamicPathParam(options)) {
this._sendErrorEmptyPath(options);
} else if (expectedResponse.search('error') >= 0) {
} else if (options.expectedResponse.search('error') >= 0) {
this._sendError(options);
} else if (method === 'HEAD') {
} else if (options.method === 'HEAD') {
this._sendHead(options);
} else {
this._sendSuccess(options);
}
}.bind(this), timeout);
}.bind(this), options.timeout);
},

/**
* @method _sendSuccess
* @param {object} options
* @param {Object} options
* @returns {void}
* @private
*/
Expand Down Expand Up @@ -146,9 +145,62 @@ MockController.prototype = extend(MockController.prototype, {

},

/**
* @method getResponseOptions
* @param {Object} req
* @param {Object} res
* @public
*/
getResponseOptions: function (req, res) {

var path = req.originalUrl.replace(this.options.urlPath, this.options.restPath);
var method = req.method;
var dir = this._findFolder(path, this.options) + '/' + method + '/';
var expectedResponse = this._getExpectedResponse(req, dir);
var preferences = this.getPreferences(this.options);
var timeout = 0;
var responseFilePath = dir + 'mock/' + expectedResponse + '.json';
var responseHeadersFilePath = dir + 'mock/' + expectedResponse + '.headers.json';

if (preferences && preferences.responseDelay) {
timeout = parseInt(preferences.responseDelay, 10);
}

if (expectedResponse === 'middleware') {
var middlewareResponse = this._acceptMiddleware(this.options, {
req: req,
res: res,
method: method,
dir: dir,
preferences: preferences,
});

if (typeof middlewareResponse === 'string') {
expectedResponse = middlewareResponse;
responseFilePath = dir + 'mock/' + expectedResponse + '.json';
responseHeadersFilePath = dir + 'mock/' + expectedResponse + '.headers.json';
} else {
return undefined;
}
}

return {
req: req,
res: res,
path: path,
method: method,
dir: dir,
expectedResponse: expectedResponse,
preferences: preferences,
timeout: timeout,
responseFilePath: responseFilePath,
responseHeadersFilePath: responseHeadersFilePath,
};
},

/**
* @method _sendError
* @param {object} options
* @param {Object} options
* @returns {void}
* @private
*/
Expand All @@ -162,13 +214,16 @@ MockController.prototype = extend(MockController.prototype, {
status = parseInt(reg[3], 10);
}

options.res.statusCode = status;
if (options.res.statusCode === 200) {
options.res.statusCode = status;
}

options.res.send(this.readFile(options.responseFilePath));
},

/**
* @method _sendError
* @param {object} options
* @param {Object} options
* @returns {void}
* @private
*/
Expand All @@ -186,7 +241,7 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _sendHead
* @param {object} options
* @param {Object} options
* @returns {void}
* @private
*/
Expand Down Expand Up @@ -229,7 +284,7 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _hasValidDynamicPathParam
* @param {object} options
* @param {Object} options
* @returns {boolean}
* @private
*/
Expand Down Expand Up @@ -267,9 +322,9 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _getResponseFiles
* @param {object} options
* @param {object} responseData
* @returns {object}
* @param {Object} options
* @param {Object} responseData
* @returns {Object}
* @private
*/
_getResponseFiles: function (options, responseData) {
Expand All @@ -294,7 +349,7 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _getExpectedResponse
* @param {object} req
* @param {Object} req
* @param {string} dir
* @returns {string}
* @private
Expand Down Expand Up @@ -324,7 +379,7 @@ MockController.prototype = extend(MockController.prototype, {
/**
* @method _getFunc
* @param {string|Array} path
* @returns {object}
* @returns {Object}
* @private
*/
_getFunc: function (path) {
Expand Down Expand Up @@ -376,8 +431,8 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _getDynamicPathParams
* @param {object} options
* @returns {object}
* @param {Object} options
* @returns {Object}
* @private
*/
_getDynamicPathParams: function (options) {
Expand Down Expand Up @@ -410,9 +465,9 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _getResponseData
* @param {object} req
* @param {Object} req
* @param {string} method
* @returns {object}
* @returns {Object}
* @private
*/
_getResponseData: function (req, method) {
Expand Down Expand Up @@ -452,8 +507,8 @@ MockController.prototype = extend(MockController.prototype, {
/**
* @method _findFolder
* @param {string} path
* @param {object} options
* @returns {object}
* @param {Object} options
* @returns {Object}
* @private
*/
_findFolder: function (path, options) {
Expand Down Expand Up @@ -497,8 +552,8 @@ MockController.prototype = extend(MockController.prototype, {

/**
* @method _writeDefaultHeader
* @param {object} customHeaders
* @param {object} res
* @param {Object} customHeaders
* @param {Object} res
* @returns {void}
* @private
*/
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-mock-server",
"version": "0.12.1",
"version": "0.13.0",
"description": "File based Node REST API mock server",
"email": "[email protected]",
"author": "Simon Mollweide <[email protected]>",
Expand Down
Loading

0 comments on commit c948890

Please sign in to comment.