A simple mock server based on koa.
It support ajax mocking, freemarker rendering, html rendering.
npm i -g @ybq/mockr
Go to directory of mockr config file mockr-config.js
.
For example the config file is under /aa/bb/cc
.
cd /aa/bb/cc
npm run mockr
mockr will find the config file named mockr-config.js
in current working directory.
Below is a config demo:
module.exports = {
restfulURLs: [
['/a', null, '/b', null],
],
pageEntries: [
{
url: url => ['', '/', '/index'].includes(url),
template: 'index.ftl',
syncDataPath: 'index-data',
},
{
url: '/tanks/shining.do',
template: 'pages/tanks/shining.ftl',
},
{
url: '/page',
template: '/aa/bb/cc.ftl',
syncDataPath: 'pageASpecial',
},
{
url: ctx => ctx.url.includes('pageEntry'),
template: 'page/entry2.ftl',
},
{
url: /^\/regexp\/page/,
template: '/page/entry3.html',
},
],
noTemplateEngine: true,
templateRoots: ['./template'],
syncDataRoot: 'sync',
controllerRoot: 'controller',
specialControllers: [
{
url: /^\/ax\//,
path: './xxx/special.js',
},
{
url: url => url.includes('love'),
path: './love/a.js',
},
],
static: [
'.',
],
async beforeController(ctx, next) {
console.info('before');
ctx.response.set('Access-Control-Allow-Origin', '*');
ctx.response.set('Access-Control-Allow-Methods', 'GET, POST, DELETE');
if (ctx.request.path === '/foo' && ctx.request.method === 'DELETE') {
ctx.body = { retCode: 200 };
} else {
await next();
}
},
async afterController(ctx, next) {
console.info('this is after handler');
await next();
},
onStartUp() {
console.info('server started');
},
};
The key concept of mockr is the mapping rule of requests. It is just a simplified koa controller. When requests comming, mockr will find controller of data file according the path of requests or from you configured mapping rule.
By default, mockr has a rule for all requests: when a request comes, mockr will find the controller in the controller path. The controller path will be the combination of controllerRoot
and request's path.
For example, you request https://3000/a/b/c
, and the controller root path you set in config file is controllers
, so the final controller path will be path.resolve(cwd, controllerRoot, '.', ctx.request.path)
,
cwd is the directory of config file. If cwd is /Usr/xxx
, then the final controller path will be /Usr/xxx/controllers/a/b/c
.
Then, mockr try to require the controller from that path, if the require result is a function, mockr will invoke it, otherwise mockr will execute ctx.body = mock(requireResult)
. So you can write a json file named c.json
or c.js
and put it in /Usr/xxx/controllers/a/b/
.
If there are params in the request URL, for example, the pattern is /name/${name}/age/${age}
, the real URL is /name/Tom/age/12
, you can specify the pattern in config file under restfulURLs
. the value of this config is an array, each item of the array represents an url pattern. In this example, the config will be like this:
restfulURLs: [
['/name', null, '/age', null],
// others
]
If rules above are not enough, you can write you own rules to match controllers in special places.
You can set specialControllers
in config file, which is an object array, each item of it contains two properties: url
and path
, url can be regexp, function or string, path is the relative controller path to controllerRoot
.
If url is regexp, mockr will execute url.test(${requestURL})
;
If url is function, mockr will execute url(ctx)
, the ctx is a koa ctx. otherwise mockr will just check url === ${requestURL}
.
If check result is true, mockr will invoke the controller specified by the item.
- Freemarker
Mockr supports freemarker template rendering. You need to config pageEntries
, templateRoots
, syncDataRoot
and static
in config file.
templateRoots
is an array of string, each item is a directory path. Usually you only need to set one item.
pageEntries
is an object array, each item contains two or three properties: url
, template
, syncDataPath
(can be omitted). url
is the same as we mentioned in specialRule
, template
is the template file of the request, syncDataRoot
just like controller, it provides sync data for the page.
syncDataRoot
is like controllerRoot
, mockr find data file by combining syncDataRoot
and syncDataPath
- HTML
If you don't use a template engine, you can set
noTemplateEngine: true
to. So when mockr dealing page request, it will find html file and send it to client.
Config the static
option to make frontend asset requests to that path. Mockr use koa-static
to server frontent assets.
The option defaultController
in config file can be string or function. If mockr meet an error calling controller, like controller not found, mockr will call defaultController.
When request comming, mockr will first check the pageEntries
rules to determin wether to render a page or just return data. If request matches in pageEntries
, and syndDataPath
for the request is set, mockr will require the data file to get sync data and render the template file in matched page entry. If syndDataPath
is not set, mockr will try to find the sync data file by default rule.
If request is not a page to render, mockr will check the special rules to find controller. If found, mockr will use the special controller.
If not found in special rules, mockr will check restfulURLs config. If found, mockr will find controller by restful rule:
params in request URL will be replaced by _param
.
For example, /name/Top/age/12
corresponds to /name/_param/age/_param
.
If still not found, mockr will try to find the controller by default rule.
- Only when you modify the config file
mockr-config.js
you need to restart mockr. Other changes of likefirst level required
mock data or controllers will apply immediately without restart.
first level required: It means files which directly required by mockr. For example, when mockr got a request /abc/dev
and matches the controller /some/place/ctrl.js
, then the controller file is first level required.
If ctrl.js requires another js file or json file, like this:
const dataJson = require('./data.json');
// ...
module.exports = (ctx) => {
ctx.body = dataJson;
};
Then the data.json is is not first level required. So if you modify the content of data.json, you need to restart mockr;
- You can set
beforeController
andafterController
to handle some logic before and after the controller logic, like set cross domain allow.
See test for more config detail
ISC