Comparing version 0.2.0 to 1.0.0
#! /usr/bin/env node | ||
var program = require('commander'); | ||
var interfake = require('./lib/server'); | ||
var Interfake = require('./lib/server'); | ||
var interfake = new Interfake(); | ||
program | ||
@@ -6,0 +7,0 @@ .version('0.0.2') |
var express = require('express'); | ||
var app = express(); | ||
var path = require('path'); | ||
app.configure(function(){ | ||
app.use(express.bodyParser()); | ||
app.use(app.router); | ||
}); | ||
function createInvalidDataException(data) { | ||
@@ -14,80 +8,89 @@ return new Error('You have to provide a JSON object with the following structure: \n' + JSON.stringify({ request : { method : '[GET|PUT|POST|DELETE]', url : '(relative URL e.g. /hello)' }, response : { code : '(HTTP Response code e.g. 200/400/500)', body : '(a JSON object)' } }, null, 4) + ' but you provided: \n' + JSON.stringify(data, null, 4)); | ||
function clearRouteForRequest(request) { | ||
var i,j; | ||
if (!app.routes[request.method]) return; | ||
for (i = app.routes[request.method].length - 1; i >= 0; i--) { | ||
if (app.routes[request.method][i].path === request.url) { | ||
console.log('Clearing existing route at ' + request.method + ': ' + request.url + ' (1/2)'); | ||
app.routes[request.method].shift(i); | ||
break; | ||
function Interfake() { | ||
var app = express(); | ||
app.configure(function(){ | ||
app.use(express.bodyParser()); | ||
app.use(app.router); | ||
}); | ||
app.post('/_request', function(req, res){ | ||
try { | ||
this.createRoute(req.body); | ||
res.send(200, { done : true }); | ||
} catch (e) { | ||
console.log('Error: ', e); | ||
res.send(400, e); | ||
} | ||
} | ||
} | ||
}); | ||
function createRoute(data) { | ||
var specifiedRequest, specifiedResponse, afterSpecifiedResponse; | ||
if (!data.request || !data.request.method || !data.request.url || !data.response || !data.response.code) { | ||
throw createInvalidDataException(data); | ||
function clearRouteForRequest(request) { | ||
var i,j; | ||
if (!app.routes[request.method]) return; | ||
for (i = app.routes[request.method].length - 1; i >= 0; i--) { | ||
if (app.routes[request.method][i].path === request.url) { | ||
console.log('Clearing existing route at ' + request.method + ': ' + request.url + ' (1/2)'); | ||
app.routes[request.method].shift(i); | ||
break; | ||
} | ||
} | ||
} | ||
if (data.response.body) { | ||
console.log('Setting up ' + data.request.method + ' ' + data.request.url + ' to return ' + data.response.code + ' with a body of length ' + JSON.stringify(data.response.body).length); | ||
} else { | ||
console.log('Setting up ' + data.request.method + ' ' + data.request.url + ' to return ' + data.response.code + ' with no body'); | ||
} | ||
// console.log('ROUTER obj: \n' + JSON.stringify(app._router.map)); | ||
this.createRoute = function createRoute (data) { | ||
var specifiedRequest, specifiedResponse, afterSpecifiedResponse; | ||
if (!data.request || !data.request.method || !data.request.url || !data.response || !data.response.code) { | ||
throw createInvalidDataException(data); | ||
} | ||
specifiedRequest = data.request; | ||
specifiedResponse = data.response; | ||
afterSpecifiedResponse = data.afterResponse; | ||
clearRouteForRequest(specifiedRequest); | ||
app[specifiedRequest.method](specifiedRequest.url, function (req, res) { | ||
var responseBody = specifiedResponse.body; | ||
console.log('Request to ' + specifiedRequest.url); | ||
res.setHeader('Content-Type', 'application/json'); | ||
if (req.query.callback) { | ||
console.log('Request is asking for jsonp'); | ||
responseBody = req.query.callback.trim() + '(' + responseBody + ')'; | ||
if (data.response.body) { | ||
console.log('Setting up ' + data.request.method + ' ' + data.request.url + ' to return ' + data.response.code + ' with a body of length ' + JSON.stringify(data.response.body).length); | ||
} else { | ||
console.log('Setting up ' + data.request.method + ' ' + data.request.url + ' to return ' + data.response.code + ' with no body'); | ||
} | ||
// console.log('ROUTER obj: \n' + JSON.stringify(app._router.map)); | ||
res.send(specifiedResponse.code, responseBody); | ||
specifiedRequest = data.request; | ||
specifiedResponse = data.response; | ||
afterSpecifiedResponse = data.afterResponse; | ||
if (afterSpecifiedResponse && afterSpecifiedResponse.endpoints) { | ||
afterSpecifiedResponse.endpoints.forEach(function (endpoint) { | ||
createRoute(endpoint); | ||
}); | ||
} | ||
}); | ||
} | ||
clearRouteForRequest(specifiedRequest); | ||
app.post('/_request', function(req, res){ | ||
try { | ||
createRoute(req.body); | ||
res.send(200, { done : true }); | ||
} catch (e) { | ||
console.log('Error: ', e); | ||
res.send(400, e); | ||
} | ||
}); | ||
app[specifiedRequest.method](specifiedRequest.url, function (req, res) { | ||
var responseBody = specifiedResponse.body; | ||
console.log('Request to ' + specifiedRequest.url); | ||
module.exports = { | ||
loadFile: function (filePath) { | ||
filePath = path.resolve(process.cwd(), filePath); | ||
res.setHeader('Content-Type', 'application/json'); | ||
if (req.query.callback) { | ||
console.log('Request is asking for jsonp'); | ||
responseBody = req.query.callback.trim() + '(' + responseBody + ')'; | ||
} | ||
file = require(filePath); | ||
res.send(specifiedResponse.code, responseBody); | ||
file.forEach(function (endpoint) { | ||
createRoute(endpoint); | ||
if (afterSpecifiedResponse && afterSpecifiedResponse.endpoints) { | ||
afterSpecifiedResponse.endpoints.forEach(function (endpoint) { | ||
createRoute(endpoint); | ||
}); | ||
} | ||
}); | ||
}, | ||
createRoute: createRoute, | ||
listen: function (port) { | ||
}; | ||
this.listen = function (port) { | ||
port = port || 3000; | ||
app.listen(port); | ||
console.log('Interfake is listening for requests on port ' + port); | ||
} | ||
}; | ||
}; | ||
} | ||
Interfake.prototype.loadFile = function (filePath) { | ||
filePath = path.resolve(process.cwd(), filePath); | ||
file = require(filePath); | ||
file.forEach(function (endpoint) { | ||
this.createRoute(endpoint); | ||
}.bind(this)); | ||
}; | ||
module.exports = Interfake; |
{ | ||
"name": "interfake", | ||
"preferGlobal": true, | ||
"version": "0.2.0", | ||
"version": "1.0.0", | ||
"author": "Daniel Hough <daniel.hough@gmail.com>", | ||
"description": "A simple way to create dummy APIs", | ||
"contributors": [ | ||
"contributors": [ | ||
{ | ||
@@ -12,4 +12,7 @@ "name": "Daniel Hough", | ||
"url": "http://danielhough.co.uk" | ||
} | ||
} | ||
], | ||
"scripts": { | ||
"test":"vows tests/test.js" | ||
}, | ||
"files": [ | ||
@@ -34,5 +37,5 @@ "example-apis", | ||
}, | ||
"dependencies" : { | ||
"express" : "3.4.5", | ||
"commander" : "2.1.0" | ||
"dependencies": { | ||
"express": "3.4.5", | ||
"commander": "2.1.0" | ||
}, | ||
@@ -44,3 +47,8 @@ "license": "MIT", | ||
"main": "./lib/server.js", | ||
"bin": "./index.js" | ||
} | ||
"bin": "./index.js", | ||
"devDependencies": { | ||
"api-easy": "^0.3.8", | ||
"vows": "^0.7.0", | ||
"request": "^2.34.0" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# Interfake: Just-add-JSON HTTP API | ||
# Interfake: Mocked JSON APIs for any platform | ||
@@ -57,6 +57,36 @@ Interfake is a tool which allows developers of client-side applications to easily create dummy APIs to develop against. Let's get started with a simple example. | ||
Interfake allows for more complex API structures, post-response endpoints and two different methods of mocking up new endpoints: by loading the file as above, or on-the-fly using an HTTP meta-API. | ||
Interfake allows for complex API structures, dynamic response endpoints and has three interfaces: the [JavaScript API](#method-1-javascript) (useful for tests), the [command line](#method-2-command-line) (like above), or on-the-fly using Interfake's [HTTP meta-API](#method-2-command-line). | ||
## Method 1: JSON File | ||
## Method 1: JavaScript | ||
Make sure you've install Interfake as a local module using `npm install interfake --save`. Then, you can start doing things like this: | ||
```javascript | ||
var Interfake = require('interfake'); | ||
var request = require('request'); // Let's use request for this example | ||
var interfake = new Interfake(); | ||
interfake.createRoute({ | ||
request: { | ||
url: '/whats-next', | ||
method: 'get' | ||
}, | ||
response: { | ||
code: 200, | ||
body: { | ||
next:'more stuff' | ||
} | ||
} | ||
}); | ||
interfake.listen(3030); // The server will listen on port 3030 | ||
request('http://localhost:3030/whats-next', function (error, response, body) { | ||
console.log(response.statusCode); // prints 200 | ||
console.log(body); // prints { next: "more stuff" } | ||
}); | ||
``` | ||
## Method 2: Command line | ||
Create a file from this template: | ||
@@ -81,3 +111,3 @@ | ||
You can create as many HTTP request/response pairs as you like. I've put some simple examples below for your copy & paste pleasure, or you can look in `/example-apis` for some more complex examples. | ||
You can create as many HTTP request/response pairs as you like. I've put some simple examples below for your copy & paste pleasure, or you can look in `/examples-command-line` for some more complex examples. | ||
@@ -90,3 +120,3 @@ Then, run the server like so: | ||
### Post-Response Endpoints | ||
### Dynamic Response Endpoints | ||
@@ -126,3 +156,3 @@ For situations where the API needs to react to mutated data, such as after a POST, PUT or DELETE request, there is an `afterResponse` property available for any existing endpoint. In this object, create another array of endpoints to be created after the original one has been created, like so: | ||
## Method 2: HTTP | ||
## Method 3: HTTP | ||
@@ -153,11 +183,13 @@ While the server is running, you can create new endpoints on-the-fly. You can make a POST request to `/_request` with a string containing the same JSON structure as above. If you were using `curl`, this is an example (smaller, for brevity). | ||
If you'd like to develop a backend-driven mobile application for iOS, Android, Windows phone or a cross-platform solution you might not yet know exactly what the backend API looks like. This is a perfect example of where Interfake is useful. You can quickly mock up some dummy APIs and work on the mobile application. In parallel, perhaps another developer will be creating the real API, or you could do something with it later. | ||
If you'd like to develop an API-driven mobile application you might not yet have a finished API available. This is a perfect example of where Interfake is useful. You can quickly mock up some dummy APIs and work on the mobile application. In parallel, perhaps another developer will be creating the real API, or you could create it later. | ||
### Automated Testing | ||
You can use Interfake to create dummy APIs which use data from your test setup with the HTTP method above, or by using a static set of test data. This is particularly useful for developing iOS Applications which uses Automated tests written in JavaScript, or developing Node.js applications which rely on external APIs. | ||
You can use Interfake to create dummy APIs which use data from your test setup with the HTTP method above, or by using a static set of test data. If you're writing your test suite using a NodeJS library, you can use the JavaScript API. | ||
The HTTP API is particularly useful for developing iOS Applications which uses Automated tests written in JavaScript, or developing Node.js applications which rely on external APIs. | ||
### Creating a static API | ||
Perhaps you have a website or mobile application which only needs static data? Deploy Interfake to a server somewhere with a JSON file serving up the data, and point your application at it. | ||
If you have a website or mobile application which only needs static data, deploy Interfake to a server somewhere with a JSON file serving up the data, and point your application at it. | ||
@@ -168,11 +200,19 @@ ## Compatibility | ||
## Version History | ||
* 1.0.0: Backwards-incompatible changes for JavaScript API, now creating an `Interfake` instance | ||
* 0.2.0: Added JSONP support | ||
* 0.1.0: Support for creating mocked JSON APIs using HTTP, JavaScript or command line | ||
## Contribute | ||
Interfake is a labour of love, created for front-end and mobile developers to increase their prototyping and development speeds. If you can contribute by getting through some issues, I would be very grateful. <3 Open Source! | ||
[![I Love Open Source](http://www.iloveopensource.io/images/logo-lightbg.png)](http://www.iloveopensource.io/projects/5319884587659fce66000943) | ||
## Plans for this module | ||
* Write some bloody tests | ||
* Better test coverage | ||
* Create a guide/some examples for how to integrate this with existing test frameworks, whether written in JavaScript or not | ||
* Improve the templating, so that a response might include a repeated structure with an incrementing counter or randomized data | ||
* Create a way to add static files in case you'd like to run a JavaScript application against it | ||
## Contributing | ||
Please feel free to make pull requests to fix bugs or add new features, and please report issues as you come across them. |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1
213
11514
3
4
89
1