@r35007/mock-server
Advanced tools
Comparing version 19.0.0 to 19.1.0
@@ -43,4 +43,5 @@ "use strict"; | ||
const id = lodashId.id || config.id || 'id'; | ||
let _data = _.cloneDeep(data); | ||
let clonedData = _.cloneDeep(data); | ||
const ids = (0, _1.flatQuery)(params[id] || query[id]); | ||
const _groupBy = (0, _1.flatQuery)(query._group)[0]; | ||
const _sort = (0, _1.flatQuery)(query._sort); | ||
@@ -58,2 +59,3 @@ const _order = (0, _1.flatQuery)(query._order); | ||
const isRange = _start || _end; | ||
delete query._group; | ||
delete query._sort; | ||
@@ -70,86 +72,109 @@ delete query._order; | ||
delete query.q; | ||
// Filters By Id | ||
if (ids.length) { | ||
_data = ids.map((id) => lodashId.getById(_data, id)).filter(Boolean); | ||
} | ||
// Partial Text Search | ||
const searchTexts = [..._text, ...q].filter(Boolean); | ||
if (searchTexts.filter(Boolean).length) { | ||
_data = _data.filter((d) => searchTexts.some((_t) => { | ||
var _a, _b; | ||
return ((_a = _.values(d) | ||
.join(', ')) === null || _a === void 0 ? void 0 : _a.toLowerCase().indexOf((_b = `${_t || ''}`) === null || _b === void 0 ? void 0 : _b.toLowerCase())) >= 0; | ||
})); | ||
} | ||
// Attribute Filter -> _like, _ne, _lt, _lte, _gt, _gte | ||
_data = _data.filter((item) => { | ||
for (let [key, val] of _.toPairs(query)) { | ||
const _val = [].concat(val).filter((v) => v !== undefined || v !== null); | ||
const path = key.replace(/(_lt|_lte|_gt|_gte|_ne|_like)$/, ''); | ||
const itemVal = _.get(item, path); | ||
const isMatched = _val.some((paramVal) => { | ||
if (/_lte$/.test(key)) | ||
return parseInt(itemVal) <= parseInt(paramVal); | ||
else if (/_lt$/.test(key)) | ||
return parseInt(itemVal) < parseInt(paramVal); | ||
else if (/_gte$/.test(key)) | ||
return parseInt(itemVal) >= parseInt(paramVal); | ||
else if (/_gt$/.test(key)) | ||
return parseInt(itemVal) > parseInt(paramVal); | ||
else if (/_ne$/.test(key)) | ||
return paramVal != itemVal; | ||
else if (/_like$/.test(key)) | ||
return new RegExp(paramVal, 'i').test(itemVal.toString()); | ||
else | ||
paramVal == itemVal; | ||
}); | ||
if (!isMatched) | ||
return false; | ||
let groupList = _.values(_.groupBy(clonedData, _groupBy)); | ||
groupList = groupList.map((groupData) => { | ||
let _data = groupData; | ||
// Automatically delete query parameters that can't be found in database | ||
Object.keys(query).forEach((key) => { | ||
for (const i in _data) { | ||
const path = key.replace(/(_lt|_lte|_gt|_gte|_ne|_like)$/, ''); | ||
if (_.has(_data[i], path) || key === 'callback' || key === '_') | ||
return; | ||
} | ||
delete query[key]; | ||
}); | ||
// Makes query.id=1,2 to query.id=[1,2] | ||
for (const key in query) { | ||
query[key] = (0, _1.flatQuery)(query[key]); | ||
} | ||
return true; | ||
// Filters By Id | ||
if (ids.length) { | ||
_data = ids.map((id) => lodashId.getById(_data, id)).filter(Boolean); | ||
} | ||
// Partial Text Search | ||
const searchTexts = [..._text, ...q].filter(Boolean); | ||
if (searchTexts.filter(Boolean).length) { | ||
_data = _data.filter((d) => searchTexts.some((_t) => { | ||
var _a, _b; | ||
return ((_a = _.values(d) | ||
.join(', ')) === null || _a === void 0 ? void 0 : _a.toLowerCase().indexOf((_b = `${_t || ''}`) === null || _b === void 0 ? void 0 : _b.toLowerCase())) >= 0; | ||
})); | ||
} | ||
// Attribute Filter -> _like, _ne, _lt, _lte, _gt, _gte | ||
_data = _data.filter((item) => { | ||
for (let [key, val] of _.toPairs(query)) { | ||
const _val = [].concat(val).filter((v) => v !== undefined || v !== null); | ||
const path = key.replace(/(_lt|_lte|_gt|_gte|_ne|_like)$/, ''); | ||
const itemVal = _.get(item, path); | ||
const isMatched = _val.some((paramVal) => { | ||
if (/_lte$/.test(key)) | ||
return parseInt(itemVal) <= parseInt(paramVal); | ||
else if (/_lt$/.test(key)) | ||
return parseInt(itemVal) < parseInt(paramVal); | ||
else if (/_gte$/.test(key)) | ||
return parseInt(itemVal) >= parseInt(paramVal); | ||
else if (/_gt$/.test(key)) | ||
return parseInt(itemVal) > parseInt(paramVal); | ||
else if (/_ne$/.test(key)) | ||
return paramVal != itemVal; | ||
else if (/_like$/.test(key)) | ||
return new RegExp(paramVal, 'i').test(itemVal.toString()); | ||
else | ||
return paramVal == itemVal; | ||
}); | ||
if (!isMatched) | ||
return false; | ||
} | ||
return true; | ||
}); | ||
// Sort and Order | ||
_data = _.orderBy(_data, _sort, _order.map((o) => `${o || ''}`.toLowerCase())); | ||
// Ranging | ||
if (isRange) { | ||
const startIndex = _start !== null && _start !== void 0 ? _start : 0; | ||
const endIndex = _end !== null && _end !== void 0 ? _end : _data.length; | ||
_data = _data.slice(startIndex, endIndex) || []; | ||
} | ||
// Pagination | ||
if (_page !== undefined) { | ||
const chunks = _.chunk(_data, _per_page !== null && _per_page !== void 0 ? _per_page : 10); | ||
const links = {}; | ||
const fullURL = `http://${req.get('host')}${req.originalUrl}`; | ||
links.first = fullURL.replace(`_page=${_page}`, '_page=1'); | ||
if (_page > 1) | ||
links.prev = fullURL.replace(`_page=${_page}`, `_page=${_page - 1}`); | ||
if (_page < chunks.length) | ||
links.next = fullURL.replace(`_page=${_page}`, `_page=${_page + 1}`); | ||
links.last = fullURL.replace(`_page=${_page}`, `_page=${chunks.length}`); | ||
res.links(links); | ||
_data = chunks[_page - 1] || []; | ||
} | ||
// Limit | ||
if (_limit !== undefined) { | ||
_data = _.take(_data, _limit) || []; | ||
} | ||
// First | ||
if (_first == 'true') { | ||
_data = _.head(_data); | ||
} | ||
// Last | ||
if (_last == 'true') { | ||
_data = _.last(_data); | ||
} | ||
// Set Headers | ||
if (_start || _end || _limit || _page) { | ||
res.setHeader('X-Total-Count', _data.length); | ||
res.setHeader('Access-Control-Expose-Headers', `X-Total-Count${_page ? ', Link' : ''}`); | ||
} | ||
if (params[id] && _.isArray(_data) && (_data === null || _data === void 0 ? void 0 : _data.length) === 0) | ||
return {}; | ||
if (params[id] && _.isArray(_data) && (_data === null || _data === void 0 ? void 0 : _data.length) === 1) | ||
return _data[0]; | ||
return _data; | ||
}); | ||
// Sort and Order | ||
_data = _.orderBy(_data, _sort, _order.map((o) => `${o || ''}`.toLowerCase())); | ||
// Ranging | ||
if (isRange) { | ||
const startIndex = _start !== null && _start !== void 0 ? _start : 0; | ||
const endIndex = _end !== null && _end !== void 0 ? _end : _data.length; | ||
_data = _data.slice(startIndex, endIndex) || []; | ||
} | ||
// Pagination | ||
if (_page !== undefined) { | ||
const chunks = _.chunk(_data, _per_page !== null && _per_page !== void 0 ? _per_page : 10); | ||
const links = {}; | ||
const fullURL = `http://${req.get('host')}${req.originalUrl}`; | ||
links.first = fullURL.replace(`_page=${_page}`, '_page=1'); | ||
if (_page > 1) | ||
links.prev = fullURL.replace(`_page=${_page}`, `_page=${_page - 1}`); | ||
if (_page < chunks.length) | ||
links.next = fullURL.replace(`_page=${_page}`, `_page=${_page + 1}`); | ||
links.last = fullURL.replace(`_page=${_page}`, `_page=${chunks.length}`); | ||
res.links(links); | ||
_data = chunks[_page - 1] || []; | ||
} | ||
// Limit | ||
if (_limit !== undefined) { | ||
_data = _.take(_data, _limit) || []; | ||
} | ||
// First | ||
if (_first == 'true') { | ||
_data = _.head(_data); | ||
} | ||
// Last | ||
if (_last == 'true') { | ||
_data = _.last(_data); | ||
} | ||
// Set Headers | ||
if (_start || _end || _limit || _page) { | ||
res.setHeader('X-Total-Count', data.length); | ||
res.setHeader('Access-Control-Expose-Headers', `X-Total-Count${_page ? ', Link' : ''}`); | ||
} | ||
if (params[id] && _.isArray(_data) && (_data === null || _data === void 0 ? void 0 : _data.length) === 0) | ||
const flattenData = _.flatten(groupList); | ||
if (params[id] && _.isArray(flattenData) && (flattenData === null || flattenData === void 0 ? void 0 : flattenData.length) === 0) | ||
return {}; | ||
if (params[id] && _.isArray(_data) && (_data === null || _data === void 0 ? void 0 : _data.length) === 1) | ||
return _data[0]; | ||
return _data; | ||
if (params[id] && _.isArray(flattenData) && (flattenData === null || flattenData === void 0 ? void 0 : flattenData.length) === 1) | ||
return flattenData[0]; | ||
return flattenData; | ||
}; | ||
@@ -156,0 +181,0 @@ default_1.insert = (req, res, data) => { |
{ | ||
"name": "@r35007/mock-server", | ||
"version": "19.0.0", | ||
"version": "19.1.0", | ||
"description": "Customize Your Own Local Mock Server", | ||
@@ -5,0 +5,0 @@ "bin": { |
268
README.md
@@ -9,6 +9,4 @@ # Mock Server[](#mock-server) [![](https://img.shields.io/npm/v/@r35007/mock-server?label=npm)](https://img.shields.io/npm/v/@r35007/mock-server?label=npm) [![](https://img.shields.io/npm/l/@r35007/mock-server?color=blue)](https://img.shields.io/npm/l/@r35007/mock-server?color=blue) [![](https://img.shields.io/npm/types/@r35007/mock-server)](https://img.shields.io/npm/types/@r35007/mock-server) | ||
## Table of contents | ||
<details> | ||
<summary>Details</summary> | ||
<summary><h2 style="padding:0;display: inline-block;">Table of contents</h2></summary> | ||
<ul dir="auto"> | ||
@@ -19,2 +17,12 @@ <li> | ||
<li> | ||
<details> | ||
<summary><a href="#routes">Routes</a></summary> | ||
<ul dir="auto"> | ||
<li> <a href="#params">Params</a> </li> | ||
<li> <a href="#delete">Delete</a> </li> | ||
<li> <a href="#serving-static-files">Serving static files</a> </li> | ||
</ul> | ||
</details> | ||
</li> | ||
<li> | ||
<p dir="auto"><a href="#cli-usage">CLI Usage</a></p> | ||
@@ -139,2 +147,115 @@ </li> | ||
## Routes | ||
Based on the example `db.json`, you'll get the following routes: | ||
```sh | ||
GET /posts | ||
GET /posts/:id | ||
POST /posts | ||
PUT /posts/:id | ||
PATCH /posts/:id | ||
DELETE /posts/:id | ||
# Same for comments | ||
``` | ||
```sh | ||
GET /profile | ||
PUT /profile | ||
PATCH /profile | ||
``` | ||
## Params | ||
### Conditions | ||
- ` ` → `==` | ||
- `_lt` → `<` | ||
- `_lte` → `<=` | ||
- `_gt` → `>` | ||
- `_gte` → `>=` | ||
- `_ne` → `!=` | ||
- `_like` → `regex match` | ||
```sh | ||
GET /posts?views_gt=9000 | ||
``` | ||
### Range | ||
- `_first` | ||
- `_last` | ||
- `_start` | ||
- `_end` | ||
- `_limit` | ||
```sh | ||
GET /posts?_start=10&_end=20 | ||
GET /posts?_start=10&_limit=10 | ||
``` | ||
### Paginate | ||
- `_page` | ||
- `_per_page` (default = 10) | ||
```sh | ||
GET /posts?_page=1&_per_page=25 | ||
``` | ||
### Sort | ||
- `_sort` | ||
```sh | ||
GET /posts?_sort=id,-views | ||
``` | ||
### Text Search | ||
- `_text` | ||
- `q` | ||
```sh | ||
GET /posts?_text=qui%20est%20esse | ||
GET /posts?q=qui%20est%20esse | ||
``` | ||
### Nested and array fields | ||
- `x.y.z...` | ||
- `x.y.z[i]...` | ||
```sh | ||
GET /foo?a.b=bar | ||
GET /foo?x.y_lt=100 | ||
GET /foo?arr[0]=bar | ||
``` | ||
### Group By | ||
- `_group` | ||
```sh | ||
GET /posts?_group=userId&_limit=1 | ||
GET /posts?_group=userId&userId=1,2&_limit=2 | ||
``` | ||
## Delete | ||
```sh | ||
DELETE /posts/1 | ||
``` | ||
## Serving static files | ||
If you create a `./public` directory, Mock Server will serve its content in addition to the REST API. | ||
You can also add custom directories using `-s/--static` option. | ||
```sh | ||
mock-server -s ./static | ||
``` | ||
## CLI Usage | ||
@@ -147,8 +268,8 @@ | ||
Options: | ||
-c, --config Path to config file [string] [default: "mock-server.json"] | ||
-P, --port Set port [number] [default: 3000] | ||
-H, --host Set host [string] [default: "localhost"] | ||
-r, --root Set root directory. [string] [default: "./"] | ||
-s, --static Set static files directory [string] [default: "./public"] | ||
-b, --base Set base route path [string] [default: ""] | ||
-c, --config Path to config file [string] [default: "mock-server.json"] | ||
-P, --port Set port [number] [default: 3000] | ||
-H, --host Set host [string] [default: "localhost"] | ||
-r, --root Set root directory. [string] [default: "./"] | ||
-s, --static Set static files directory [string] [default: "./public"] | ||
-b, --base Set base route path [string] [default: ""] | ||
--db Path to database file [string] | ||
@@ -159,17 +280,17 @@ --middlewares, --md Path to middlewares file [string] | ||
--rewriters, --rw Path to Rewriter file [string] | ||
--id Set database id property [string] [default: "id"] | ||
--id Set database id property [string] [default: "id"] | ||
--init Create a sample server files [boolean] [default: false] | ||
--dbMode, --dm Set Db mode [string] [default: "mock"] [choices: "mock", "dev", "multi"] | ||
--snapshots, --ss Set snapshots directory [string] [default: "./"] | ||
--reverse, --rv Generate Route in revere order [boolean] [default: false] | ||
--readOnly, --ro Allow only GET requests [boolean] [default: false] | ||
--noCors, --nc Disable Cross-Origin Resource Sharing [boolean] [default: false] | ||
--noGzip, --ng Disable GZIP Content-Encoding [boolean] [default: false] | ||
--noCache, --nch Disable Caching [boolean] [default: true] | ||
--bodyParser, --bp Enable body-parser [boolean] [default: true] | ||
--cookieParser, --cp Enable cookie-parser [boolean] [default: true] | ||
-l, --logger Enable logger [boolean] [default: true] | ||
--log Enable Setter Logs [boolean] [default: false] | ||
-w, --watch Watch for changes [boolean] [default: false] | ||
-q, --quiet Prevent console logs [boolean] [default: false] | ||
--dbMode, --dm Set Db mode [string] [default: "mock"] [choices: "mock", "dev", "multi"] | ||
--snapshots, --ss Set snapshots directory [string] [default: "./"] | ||
--reverse, --rv Generate Route in revere order [boolean] [default: false] | ||
--readOnly, --ro Allow only GET requests [boolean] [default: false] | ||
--noCors, --nc Disable Cross-Origin Resource Sharing [boolean] [default: false] | ||
--noGzip, --ng Disable GZIP Content-Encoding [boolean] [default: false] | ||
--noCache, --nch Disable Caching [boolean] [default: true] | ||
--bodyParser, --bp Enable body-parser [boolean] [default: true] | ||
--cookieParser, --cp Enable cookie-parser [boolean] [default: true] | ||
-l, --logger Enable logger [boolean] [default: true] | ||
--log Enable Setter Logs [boolean] [default: false] | ||
-w, --watch Watch for changes [boolean] [default: false] | ||
-q, --quiet Prevent console logs [boolean] [default: false] | ||
-h, --help Show help [boolean] | ||
@@ -197,3 +318,4 @@ -v, --version Show version number [boolean] | ||
or | ||
<details> | ||
<summary>View detailed example</summary> | ||
@@ -253,2 +375,4 @@ ```js | ||
</details> | ||
Now go to terminal and type the following command to start the Mock Server. | ||
@@ -267,3 +391,3 @@ | ||
Create `db.json` | ||
Create `db.json` or `db.jsonc` or `db.json5` | ||
@@ -383,8 +507,8 @@ ```jsonc | ||
All available methods to create a route. | ||
`server.js` | ||
<details> | ||
<summary>All available methods to create a route. `server.js`</summary> | ||
```js | ||
const { MockServer } = require('@r35007/mock-server'); | ||
const mockServer = MockServer.Create({ root: __dirname }); | ||
const mockServer = MockServer.Create({ root: \_\_dirname }); | ||
const app = mockServer.app; | ||
@@ -394,46 +518,48 @@ const resources = mockServer.resources(); | ||
middlewares = [ | ||
(req, res, next) => { | ||
next(); | ||
}, | ||
(req, res, next) => { | ||
next(); | ||
}, | ||
(req, res, next) => { | ||
next(); | ||
}, | ||
(req, res, next) => { | ||
next(); | ||
}, | ||
]; | ||
const db = resources | ||
.create('/todos', ...middlewares) // can give n number of middlewares and names here | ||
.send('My Response', mockServer.config.dbMode) // this value will be set to `mock` or `fetch` based on dbMode. alias rely | ||
.id('todos') | ||
.description('todos route') | ||
.mock({ userId: 1, id: 1, title: 'Marvel', completed: false }) | ||
.fetch('https://jsonplaceholder.typicode.com/todos') | ||
.mockFirst(false) | ||
.statusCode(200) // alias status(200) can also be used | ||
.delay(0) // delay in milliseconds | ||
.fetchCount(1) | ||
.skipFetchError(false) | ||
.directUse(false) | ||
.headers({}) // Set response Headers | ||
.done({ log: true }); // Make sure to call done method to create the route. | ||
.create('/todos', ...middlewares) // can give n number of middlewares and names here | ||
.send('My Response', mockServer.config.dbMode) // this value will be set to `mock` or `fetch` based on dbMode. alias rely | ||
.id('todos') | ||
.description('todos route') | ||
.mock({ userId: 1, id: 1, title: 'Marvel', completed: false }) | ||
.fetch('https://jsonplaceholder.typicode.com/todos') | ||
.mockFirst(false) | ||
.statusCode(200) // alias status(200) can also be used | ||
.delay(0) // delay in milliseconds | ||
.fetchCount(1) | ||
.skipFetchError(false) | ||
.directUse(false) | ||
.headers({}) // Set response Headers | ||
.done({ log: true }); // Make sure to call done method to create the route. | ||
console.log(db); | ||
/* db will return the generated db object. This will not be added to the mockserver db until we call done() method | ||
{ | ||
"/todos": { | ||
"id":"todos", | ||
"description": "todos route", | ||
"mock":{ | ||
"userId": 1, | ||
"id": 1, | ||
"title": "Marvel", | ||
"completed": false | ||
}, | ||
"fetch": "https://jsonplaceholder.typicode.com/todos", | ||
"mockFirst": false, | ||
"statusCode": 200, | ||
"delay": 0, | ||
"fetchCount": 1, | ||
"skipFetchError": false, | ||
"directUse": false, | ||
"headers": {} | ||
} | ||
"/todos": { | ||
"_config": true, | ||
"id":"todos", | ||
"description": "todos route", | ||
"mock":{ | ||
"userId": 1, | ||
"id": 1, | ||
"title": "Marvel", | ||
"completed": false | ||
}, | ||
"fetch": "https://jsonplaceholder.typicode.com/todos", | ||
"mockFirst": false, | ||
"statusCode": 200, | ||
"delay": 0, | ||
"fetchCount": 1, | ||
"skipFetchError": false, | ||
"directUse": false, | ||
"headers": {} | ||
} | ||
} | ||
@@ -445,6 +571,10 @@ */ | ||
mockServer.startServer(); | ||
``` | ||
```` | ||
Please check [resources](#resources) api for more custom option reference. | ||
</details> | ||
## Middlewares | ||
@@ -483,3 +613,3 @@ | ||
}; | ||
``` | ||
```` | ||
@@ -486,0 +616,0 @@ `server.js` |
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
682910
18018
1675