Skip to content

Commit 3ff990b

Browse files
committed
Capture mode and verbose mode added
1 parent c3e510f commit 3ff990b

File tree

4 files changed

+121
-36
lines changed

4 files changed

+121
-36
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.0.4 (2018-02-06)
2+
3+
### Features:
4+
5+
- **Capture Mode**: Now you can automatically generate mock files from your api responses.
6+
- **Verbose Mode**: `--verbose` cli parameter added to use verbose mode of connect-api-mocker.
7+
18
## 1.0.3 (2018-01-12)
29

310
### Features:

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ That command will start to serve your mocks on port `9090` by default.
2020

2121
## Arguments
2222

23-
`mockit` command has 3 available arguments.
23+
`mockit` command has 4 available arguments.
2424

25-
[-p | --port] with default value `9090`,
25+
[-p | --port] with default value `9090`,
2626
[-f | --fromPath] with default value `/`,
2727
[-t | --toPath] with default value ``
28+
[-c | --capture] with default value `false`
29+
[-v | --verbose] with default value `false`
2830

2931
These arguments are optional. You can use `mockit` command with any one of them or any combination of them.
3032

@@ -36,9 +38,9 @@ You can see usage examples below:
3638

3739
Or you can combine any of them like:
3840

39-
`mockit --port=8989 --fromPath=/api --toPath=/mapi`
41+
`mockit --port=8989 --fromPath=/api --toPath=/mapi`
4042

41-
Or
43+
Or
4244

4345
`mockit -p 8989 -f '/api -t '/mapi'`
4446

@@ -96,3 +98,22 @@ module.exports = {
9698
}
9799
```
98100

101+
### Capture mode
102+
103+
With capture mode, you can automatically create mock files from your api origin responses over proxy. You can enable capture mode by `--capture` (or `-c`) command line parameter or `capture` property in config file:
104+
105+
```js
106+
module.exports = {
107+
port: 9090,
108+
map: {
109+
'/api': {
110+
target: 'mocks/api',
111+
proxy: 'https://api.yourdomain.com',
112+
capture: true
113+
}
114+
}
115+
}
116+
```
117+
118+
When capture mode enabled, if you don't have a mock file for a request and if you have a proxy definition, a mock file will automatically generated for you for successful responses from your origin.
119+

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
{
22
"name": "cli-api-mocker",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "CLI wrapper for connect-api-mocker",
55
"main": "src/index.js",
66
"dependencies": {
77
"command-line-args": "^4.0.7",
8-
"connect-api-mocker": "^1.3.5",
8+
"connect-api-mocker": "^1.3.6",
99
"cors": "^2.8.4",
1010
"express": "^4.15.4",
11-
"http-proxy-middleware": "^0.17.4"
11+
"http-proxy-middleware": "^0.17.4",
12+
"mkdirp": "^0.5.1"
1213
},
1314
"devDependencies": {},
1415
"scripts": {

src/index.js

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,71 +5,127 @@ var apiMocker = require('connect-api-mocker');
55
var bodyParser = require('body-parser')
66
var proxy = require('http-proxy-middleware');
77
var cors = require('cors');
8+
var fs = require('fs');
9+
var pth = require('path');
10+
var mkdirp = require('mkdirp');
811
var commandLineArgs = require('command-line-args');
912
var defaultPortValue = 9090;
1013
var defaultFromPathValue = '/';
1114
var defaultToPathValue = '';
1215
var optionDefinitions = [
1316
{ name: 'port', alias: 'p', type: Number, defaultValue: defaultPortValue },
1417
{ name: 'fromPath', alias: 'f', type: String, defaultValue: defaultFromPathValue },
15-
{ name: 'toPath', alias: 't', type: String, defaultValue: defaultToPathValue }
18+
{ name: 'toPath', alias: 't', type: String, defaultValue: defaultToPathValue },
19+
{ name: 'capture', alias: 'c', type: Boolean, defaultValue: false },
20+
{ name: 'verbose', alias: 'v', type: Boolean, defaultValue: false }
1621
];
1722

23+
function escapeRegExp(str) {
24+
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
25+
}
26+
1827
var options = commandLineArgs(optionDefinitions);
1928

2029
var app = express();
2130

2231
var mapping = {};
2332

24-
mapping[options.fromPath] = options.toPath;
33+
mapping[options.fromPath] = {
34+
target: options.toPath
35+
};
2536

2637
var defaultConfig = {
27-
port: options.port,
28-
map: mapping
38+
port: options.port,
39+
map: mapping
2940
};
3041
var config = defaultConfig;
3142

3243
try {
33-
var loadedConfig = require(path.resolve(process.cwd() , 'mock.config.js'));
34-
console.log('Config file found mocking!');
44+
var loadedConfig = require(path.resolve(process.cwd() , 'mock.config.js'));
45+
console.log('Config file found mocking!');
3546

36-
if (config.port === defaultPortValue && loadedConfig.port) {
37-
config.port = loadedConfig.port;
38-
}
47+
if (config.port === defaultPortValue && loadedConfig.port) {
48+
config.port = loadedConfig.port;
49+
}
3950

40-
var mapKeys = Object.keys(config.map);
41-
if (loadedConfig.map) {
42-
mapKeys.forEach(function (mapKey) {
43-
loadedConfig.map[mapKey] = config.map[mapKey];
44-
});
45-
config.map = loadedConfig.map;
46-
}
51+
var mapKeys = Object.keys(config.map);
52+
if (loadedConfig.map) {
53+
mapKeys.forEach(function (mapKey) {
54+
loadedConfig.map[mapKey] = config.map[mapKey];
55+
});
56+
config.map = loadedConfig.map;
57+
}
4758
} catch (error) {
48-
// there is no config
59+
// there is no config
4960
}
5061

51-
app.use(cors())
62+
if (options.verbose) {
63+
Object.keys(config.map).forEach(function (key) {
64+
config.map[key].verbose = true;
65+
});
66+
}
5267

53-
for(var path in config.map) {
68+
app.use(cors());
5469

55-
var conf = config.map[path];
70+
for(var path in config.map) {
71+
(function (basePath) {
72+
var conf = config.map[basePath];
5673

5774
if (conf.proxy) {
58-
conf.nextOnNotFound = true;
75+
conf.nextOnNotFound = true;
5976
}
6077

61-
app.use(path, apiMocker(conf));
62-
console.log(`Mocking enabled: ${path} => ${conf}`);
78+
app.use(basePath, apiMocker(conf));
79+
console.log(`Mocking enabled: ${basePath} => ${conf.target || conf}`);
6380

6481
if (conf.proxy) {
65-
console.log(`Proxy enabled: ${path} => ${conf.proxy}`);
66-
if (typeof conf.proxy == 'string') {
67-
config.proxy = {
68-
target: conf.proxy
69-
}
82+
console.log(`Proxy enabled: ${basePath} => ${conf.proxy}`);
83+
if (typeof conf.proxy == 'string') {
84+
conf.proxy = {
85+
target: conf.proxy
7086
}
71-
app.use(path, proxy(conf.proxy));
87+
}
88+
89+
if (conf.capture || options.capture) {
90+
console.log('Capture Mode enabled for mocks!');
91+
92+
conf.proxy.onProxyRes = function(proxyRes, req, res) {
93+
var body = "";
94+
if (proxyRes.statusCode < 404) {
95+
proxyRes.on('data', function(data) {
96+
data = data.toString('utf-8');
97+
body += data;
98+
});
99+
100+
proxyRes.on('end', function() {
101+
var requestedFilePath = req.path.replace(new RegExp('^(\/)?' + escapeRegExp(basePath)), '')
102+
var targetPath = pth.join(conf.target || conf, requestedFilePath);
103+
104+
var contentType = 'json';
105+
if (proxyRes.headers['content-type'].indexOf('xml') > -1) {
106+
contentType = 'xml';
107+
}
108+
109+
mkdirp.sync(targetPath);
110+
111+
var targetFile = pth.join(targetPath, req.method + '.' + contentType);
112+
113+
if (!fs.existsSync(targetFile)) {
114+
fs.writeFileSync(targetFile, body);
115+
console.log('[Capture Mode] New mock file saved to ' + targetFile);
116+
}
117+
});
118+
}
119+
}
120+
}
121+
122+
app.use(basePath, proxy(conf.proxy));
123+
} else {
124+
if (conf.capture || options.capture) {
125+
console.error('You can not use capture mode without defining a proxy.');
126+
}
72127
}
128+
})(path);
73129
}
74130

75131
app.listen(config.port, function () {

0 commit comments

Comments
 (0)