mini-mock-api
Advanced tools
Comparing version 0.0.1 to 0.2.0
var API = require('../lib/mini-mock-api'); | ||
var server = new API({ | ||
BASE_PATH: '/api/v2', | ||
PORT: 8080, | ||
MOCK_FILE_PATH: 'mock-files', | ||
ID_ATTRIBUTE: '_id' | ||
basePath: '/api/v1', | ||
port: 8080, | ||
mockPath: 'mock-files', | ||
idAttribute: '_id' | ||
}); | ||
@@ -21,2 +21,12 @@ | ||
//add custom post method localhost:8080/api/v1/custom | ||
server.post('custom', function(request, response){ | ||
response.json({status: 'okay'}); | ||
}); | ||
//add custom post method localhost:8080/root | ||
server.postFromRoot('root', function(request, response){ | ||
response.json({status: 'okay'}); | ||
}); | ||
server.start(); |
@@ -5,74 +5,80 @@ 'use strict'; | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var _ = require('lodash-node'); | ||
var Q = require('q'); | ||
var fs_readFile = Q.denodeify(fs.readFile); | ||
var customMethods = [ | ||
'get', 'post', 'put', 'delete' | ||
]; | ||
var MiniMockAPI = function(options){ | ||
this.defaults = { | ||
MOCK_FILE_PATH: 'mocks', | ||
BASE_PATH: '/api', | ||
PORT: 8080, | ||
ID_ATTRIBUTE: 'uuid', | ||
SORT_PARAMETER: 'sortOrder' | ||
mockPath: 'mocks', | ||
basePath: '/api', | ||
port: 8080, | ||
idAttribute: 'uuid', | ||
sortParameter: 'sortOrder' | ||
}; | ||
this.options = _.extend(this.defaults, options); | ||
this.app = express(); | ||
return this; | ||
}; | ||
/* | ||
* Handle all API requests with json files found in file system (./mocks). | ||
* If a file is not found the server assumes that a single item was requested | ||
* and tries to search a specific id in the parent collection | ||
* e.g. for tasks/123 it will search in tasks.json for an item with ID_ATTRIBUTE === 123 | ||
* | ||
*/ | ||
this.app.get(this.options.BASE_PATH + '/*', function(request, response){ | ||
var strippedRequestPath = request.path.substring(this.options.BASE_PATH.length), | ||
filename = this.getFilename(strippedRequestPath); | ||
fs_readFile(filename, 'utf8').then( | ||
/* | ||
* Handle all API requests with json files found in file system (./mocks). | ||
* If a file is not found the server assumes that a single item was requested | ||
* and tries to search a specific id in the parent collection | ||
* e.g. for tasks/123 it will search in tasks.json for an item with idAttribute === 123 | ||
* | ||
*/ | ||
MiniMockAPI.prototype.initMockRoute = function(filePath){ | ||
this.app.get(filePath, function(request, response){ | ||
var strippedRequestPath = request.path.substring(this.options.basePath.length), | ||
fileName = this.getFileName(strippedRequestPath); | ||
function handleFileFound(data){ | ||
var responseData = sort(JSON.parse(data), request.query[this.options.SORT_PARAMETER]); | ||
console.log('Serving: ' + filename); | ||
response.json(this.decorate(responseData)); | ||
}.bind(this), | ||
fs_readFile(fileName, 'utf8').then( | ||
function handleError(){ | ||
var splitted = splitPathInIdAndPath(strippedRequestPath); | ||
if(splitted){ | ||
fs_readFile(this.getFilename(splitted.path), 'utf8').then( | ||
function handleFileFound(data){ | ||
var responseData = sort(JSON.parse(data), request.query[this.options.sortParameter]); | ||
console.log('Serving: ' + fileName); | ||
response.json(this.decorate(responseData)); | ||
}.bind(this), | ||
function handleSingleItem(data){ | ||
var queryObj = {}; | ||
function handleError(){ | ||
var splitted = splitPathInIdAndPath(strippedRequestPath); | ||
if(splitted){ | ||
fs_readFile(this.getFileName(splitted.path), 'utf8').then( | ||
queryObj[this.options.ID_ATTRIBUTE] = splitted.id; | ||
function handleSingleItem(data){ | ||
var queryObj = {}; | ||
//search single item | ||
var foundItem = _.findWhere(JSON.parse(data), queryObj); | ||
//try again with number instead of string | ||
if(!foundItem){ | ||
queryObj[this.options.ID_ATTRIBUTE] = parseInt(splitted.id, 10); | ||
foundItem = _.findWhere(JSON.parse(data), queryObj); | ||
} | ||
if(foundItem){ | ||
console.log('Serving: ' + this.getFilename(splitted.path) + ' /' + splitted.id); | ||
response.json(this.decorate(foundItem)); | ||
} else { | ||
queryObj[this.options.idAttribute] = splitted.id; | ||
//search single item | ||
var foundItem = _.findWhere(JSON.parse(data), queryObj); | ||
//try again with number instead of string | ||
if(!foundItem){ | ||
queryObj[this.options.idAttribute] = parseInt(splitted.id, 10); | ||
foundItem = _.findWhere(JSON.parse(data), queryObj); | ||
} | ||
if(foundItem){ | ||
console.log('Serving: ' + path.join(this.getFileName(splitted.path), splitted.id)); | ||
response.json(this.decorate(foundItem)); | ||
} else { | ||
response.sendStatus(404); | ||
} | ||
}.bind(this), | ||
function(err) { | ||
console.log('No mock data found:', strippedRequestPath); | ||
response.sendStatus(404); | ||
} | ||
}.bind(this), | ||
}.bind(this) | ||
); | ||
} | ||
}.bind(this) | ||
); | ||
}.bind(this)); | ||
} | ||
function(err) { | ||
console.log(err); | ||
response.sendStatus(404); | ||
} | ||
); | ||
} | ||
}.bind(this) | ||
); | ||
}.bind(this)); | ||
return this; | ||
}; | ||
/* | ||
@@ -85,21 +91,42 @@ * This function can be overridden. Allows to modify responses globally. | ||
/* | ||
* Configure express mock route (has to be set up here because custom routes should be defined earlier) | ||
* and start server | ||
*/ | ||
MiniMockAPI.prototype.start = function() { | ||
this.expressInstance = this.app.listen(this.options.PORT); | ||
console.log('Listening on:', this.options.PORT); | ||
this.initMockRoute(path.join(this.options.basePath, '*')); | ||
this.expressInstance = this.app.listen(this.options.port); | ||
console.log('Listening on:', this.options.port); | ||
}; | ||
//Stop server | ||
MiniMockAPI.prototype.stop = function() { | ||
if(this.expressInstance){ | ||
this.expressInstance.close(); | ||
console.log('Stopped listening on:', this.options.PORT); | ||
console.log('Stopped listening on:', this.options.port); | ||
} | ||
}; | ||
MiniMockAPI.prototype.getFilename = function(path) { | ||
return process.cwd() + '/' + this.options.MOCK_FILE_PATH + path + '.json'; | ||
/* | ||
* adds convenient functions for custom routes | ||
* e.g. server.post('abc', function(req, res)) instead of server.app.post(server.options.basePath ...) | ||
*/ | ||
customMethods.forEach(function(method){ | ||
MiniMockAPI.prototype[method] = function(relativeRoute, fn) { | ||
this.app[method](path.join(this.options.basePath, relativeRoute), fn); | ||
}; | ||
MiniMockAPI.prototype[method + 'FromRoot'] = function(absoluteRoute, fn) { | ||
this.app[method](absoluteRoute, fn); | ||
}; | ||
}); | ||
// get filename relative to mock path | ||
MiniMockAPI.prototype.getFileName = function(filePath) { | ||
return path.join(process.cwd(), this.options.mockPath, filePath+'.json'); | ||
}; | ||
// split path in subpath and uuid | ||
var splitPathInIdAndPath = function(path){ | ||
var parts = path.split('/'); | ||
var splitPathInIdAndPath = function(filePath){ | ||
var parts = filePath.split('/'); | ||
if(parts.length > 0){ | ||
@@ -106,0 +133,0 @@ var id = parts.pop(); |
{ | ||
"name": "mini-mock-api", | ||
"version": "0.0.1", | ||
"version": "0.2.0", | ||
"description": "Lightweight node.js API mock server, route calls to static JSON files", | ||
@@ -5,0 +5,0 @@ "main": "lib/mini-mock-api.js", |
@@ -24,11 +24,11 @@ # mini-mock-api | ||
`GET localhost:8080/cars` | ||
`GET localhost:8080/api/v1/cars` | ||
returns all cars inside cars.json | ||
`GET localhost:8080/cars/123` | ||
`GET localhost:8080/api/v1/cars/1` | ||
returns one car with the id == 123 | ||
returns one car with the id == 1 | ||
`GET localhost:8080/oldschool/carriages` | ||
`GET localhost:8080/api/v1/oldschool/carriages` | ||
@@ -47,3 +47,5 @@ returns all items from oldschool/carriages.json | ||
var myApi = new API({ | ||
BASE_PATH: '/api/v1', | ||
basePath: '/api/v1', | ||
mockPath: 'mock-files', | ||
idAttribute: '_id' | ||
}); | ||
@@ -53,15 +55,41 @@ myApi.start(); | ||
see examples/example.js | ||
To run the server go to the script directory (path options are relative to your execution path): | ||
``` | ||
cd examples | ||
node example.js | ||
``` | ||
Open your browser and go to `localhost:8080/api/v1/todos` | ||
## Options | ||
``` | ||
{ | ||
MOCK_FILE_PATH: 'mocks', //directory to mock files relative to path of script | ||
BASE_PATH: '/api', //base path for api calls -> localhost:8080/api/... | ||
PORT: 8080, | ||
ID_ATTRIBUTE: 'uuid', //the id property to search for when requesting api/cars/123 | ||
SORT_PARAMETER: 'sortOrder' //the GET parameter for sort orders e.g. api/cars?sortOrder=+name | ||
var options = { | ||
mockPath: 'mocks', //directory to mock files relative to path of script | ||
basePath: '/api/v1', //base path for api calls -> localhost:8080/api/v1/... | ||
port: 8080, | ||
idAttribute: 'uuid', //the id property to search for when requesting api/v1/cars/123 | ||
sortParameter: 'sortOrder' //the GET parameter for sort orders e.g. api/v1/cars?sortOrder=+name | ||
} | ||
var myApi = new API(options); | ||
``` | ||
## Custom Routes | ||
If static JSON files are not sufficient you can also add custom routes by defining your own request handler functions. Custom routes are supported for GET, POST, PUT and DELETE methods: | ||
``` | ||
myApi.post('custom/status', function(request, response){ | ||
response.json({status: 'okay'}); | ||
}); | ||
``` | ||
`-> localhost:8080/api/v1/custom/status` | ||
Please note that custom routes are relativ to your 'basePath' property. If you need a route outside of your API scope use the '[get|post|put|delete]FromRoot' method: | ||
``` | ||
myApi.postFromRoot('/ping', function(request, response){ | ||
response.json({hello: 'there'}); | ||
}); | ||
``` | ||
`-> localhost:8080/ping` | ||
## Decorate | ||
@@ -68,0 +96,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10968
8
212
111