# @andremao/mockdb

> 这是一个支持 **热加载配置文件**、**JSON 文件持久化**、**模块化** 来管理 `mock` 请求的 Express 中间件模块

Latest version **1.1.17** (published 2020-10-14) · MIT license · 0 weekly downloads

## Install

```sh
npm install @andremao/mockdb
pnpm add @andremao/mockdb
yarn add @andremao/mockdb
bun add @andremao/mockdb
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.1.17 |
| Published | 2020-10-14 |
| First published | 2020-07-15 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 4 |
| Unpacked size | 14.6 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| GitHub stars | 2 |
| Author | andremao |
| Maintainers | maodun2npm |

## Links

- npm: https://www.npmjs.com/package/@andremao/mockdb
- Repository: https://github.com/andremao/mockdb
- Issues: https://github.com/andremao/mockdb/issues
- npm.io page: https://npm.io/package/@andremao/mockdb

## Dependencies (4)

- [lowdb](https://npm.io/package/lowdb.md) ^1.0.0
- [lodash](https://npm.io/package/lodash.md) ^4.17.19
- [mockjs](https://npm.io/package/mockjs.md) ^1.1.0
- [url-pattern](https://npm.io/package/url-pattern.md) ^1.0.3

## Recent versions

- 1.1.17 (latest) — 2020-10-14
- 1.1.16 — 2020-08-26
- 1.1.15 — 2020-08-25
- 1.1.13 — 2020-08-25
- 1.1.12 — 2020-08-25
- 1.1.11 — 2020-08-25
- 1.1.10 — 2020-08-25
- 1.1.9 — 2020-08-25
- 1.1.8 — 2020-08-25
- 1.1.7 — 2020-08-24
- 1.1.6 — 2020-08-24
- 1.1.5 — 2020-08-24
- 1.1.3 — 2020-08-24
- 1.1.2 — 2020-08-24
- 1.1.1 — 2020-08-24
- … 6 more at https://npm.io/package/@andremao/mockdb/versions

## README

## MockDB

这是一个支持 **热加载配置文件**、**JSON 文件持久化**、**模块化** 来管理 `mock` 请求的 Express 中间件模块

## 安装

`npm i -D @andremao/mockdb`

## 使用

1. 在项目的**根目录下**新建目录 `mockdb/mock`，在此目录下创建的所有 `*.js` 文件都将自动识别为 `mockdb` 配置文件

2. 当调用 service 方法获取 service 实例时，持久化的 `*.json` 文件会自动生成在 `mockdb/db/*.json` 下

3. `mockdb` 配置文件内容如下（假设存在 `mockdb/mock/user.js` 配置文件）：

   ```javascript
   const service = require('@andremao/mockdb').service('user.json');
   const mockjs = require('mockjs');

   module.exports = {
     // 要被 mockjs 拦截的请求集
     requests: [
       // 增
       {
         // 请求类型支持大小写
         method: 'post',
         // 注意：
         //   mockjs 只能拦截本地主机地址（如：http://localhost:8080/user）
         //   mockjs 不能拦截跨域的线上地址（如：http://api.itcast.cn/user）
         url: '/user',
         handler(req, res) {
           console.log(req.body, 'req.body');
           // 插入单个，返回插入之后的对象（包含 id）
           const user = service.create(req.body);
           res.json({
             code: 200,
             message: '添加用户成功',
             data: user,
           });
         },
       },
       // 删
       {
         // 可以通过 active 配置该请求的激活状态，默认为激活
         active: false,
         method: 'delete',
         url: '/user/:id',
         handler(req, res) {
           console.log(req.params, 'req.params');
           // 根据 id 删除，返回被删除的对象
           const user = service.delete(req.params.id);
           res.json({
             code: 200,
             message: 'ok',
             user,
           });
         },
       },
       // 改
       {
         method: 'patch',
         url: '/user/:id',
         handler(req, res) {
           console.log(req.params, 'req.params');
           console.log(req.body, 'req.body');
           // 根据 id 补丁更新，返回更新后的对象
           const user = service.patch(req.params.id, req.body);
           res.json({
             code: 200,
             message: 'ok',
             user,
           });
         },
       },
       // 根据 id 查询
       {
         method: 'get',
         // 支持动态路由参数
         url: '/user/:id',
         handler(req, res) {
           const { id } = req.params;
           // 根据 id 查找用户
           const user = service.find(id);
           res.json({
             code: 200,
             message: '获取用户信息成功',
             data: user,
           });
         },
       },
       // 分页查询
       {
         method: 'GET',
         url: '/users',
         handler(req, res) {
           console.log(req.query, 'req.query');

           // // 如果json文件中没有数据，则自动生成100条
           // const { list } = service.getState();
           // if (!list || !list.length) {
           //   service.batchCreate(
           //     mockjs.mock({
           //       'list|100': [{ name: '@CNAME()', 'age|15-60': 1, id: '@GUID()' }],
           //     }).list,
           //   );
           // }
           // // /如果json文件中没有数据，则自动生成100条

           const { page, size, name, ageType } = req.query;
           const age = parseInt(req.query.age);
           const result = service.pagingQuery({
             page,
             size,
             // 过滤，就是数组的 filter 方法的回调函数
             filter(user) {
               const results = [];
               if (name) {
                 results.push(user.name.includes(name));
               }
               if (!isNaN(age)) {
                 switch (ageType) {
                   case 'eq':
                     results.push(user.age === age);
                     break;
                   case 'ne':
                     results.push(user.age !== age);
                     break;
                   case 'gt':
                     results.push(user.age > age);
                     break;
                   case 'lt':
                     results.push(user.age < age);
                     break;
                   case 'ge':
                     results.push(user.age >= age);
                     break;
                   case 'le':
                     results.push(user.age <= age);
                     break;
                 }
               }
               return results.every((v) => v);
             },
             // 排序，就是数组的 sort 方法的回调函数
             sort(user1, user2) {
               // 何时把 user1 放到 user2 后面? 当 user1.age > user2.age 时
               if (user1.age > user2.age) return 1;
               // 何时把 user1 放到 user2 前面? 当 user1.age > user2.age 时
               if (user1.age < user2.age) return -1;
               // 何时不用换位置? 当 user1.age === user2.age 时
               return 0;

               // 补充顺明:
               // 1 上面的代码等价：return user1.age - user2.age; 虽然代码量少，但不推荐，因为可读性差
               // 2 不要直接使用 return user1.age > user2.age; 因为在不同运行环境下执行结果可能不一致，有坑！！！
             },
           });
           res.json({
             code: 200,
             message: 'ok',
             ...result,
           });
         },
       },
     ],
   };
   ```

4. 在 vue 中使用，修改 `vue.config.js` 配置文件：

   ```javascript
   const mockdb = require('@andremao/mockdb');
   const bodyParser = require('body-parser');

   module.exports = {
     devServer: {
       before(app) {
         // 判断是否为开发环境
         if (process.env.NODE_ENV.toUpperCase() === 'DEVELOPMENT') {
           app.use(bodyParser.json(), mockdb.middleware());
         }
       },
     },
   };
   ```

   Demo 仓库地址：https://github.com/andremao/vue-mockdb-demo

5. 重启项目即可，并支持热加载，后续改动 `mockdb/mock/*.js` 与 `mockdb/db/*.json` 文件无需重启

6. 可以实现 **mock 环境** 与 **线上环境** 混搭：

   1. 使用代理服务器（**推荐**），例如：Vue CLI 配置，详见：https://cli.vuejs.org/zh/config/#devserver-proxy

      ```javascript
      const mockdb = require('@andremao/mockdb');
      const bodyParser = require('body-parser');

      module.exports = {
        devServer: {
          before(app) {
            // 判断是否为开发环境
            if (process.env.NODE_ENV.toUpperCase() === 'DEVELOPMENT') {
              app.use(bodyParser.json(), mockdb.middleware());
            }
          },
          proxy: {
            '/api': {
              target: 'http://some.api.itcast.cn',
              changeOrigin: true,
              pathRewrite: {
                '^/api': '',
              },
            },
          },
        },
      };
      ```

   2. 或者，配置 axios 的请求拦截器，动态设置 baseURL

      发请求：

      ```javascript
      axios.post('/login?ismock=1', { uname: 'andremao', pwd: 'qwe123' });
      ```

      axios：

      ```javascript
      // 创建 axios 请求实例
      const request = axios.create({
        baseURL: 'http://api.itcast.cn/',
      });

      // 请求拦截器
      request.interceptors.request.use((cfg) => {
        // 如果是 mock 则把请求 baseURL 改成 本地地址，不然 mockjs 拦截不到
        if (cfg.url.includes('ismock=1')) {
          cfg.baseURL = 'http://localhost:8080';
        }
        return cfg;
      });
      ```

## API

### mockdb

```javascript
const mockdb = require('@andremao/mockdb');
```

#### mockdb.middleware()

获取中间件处理函数

#### mockdb.service(jsonFileName)

返回能操作 JSON 文件的 service 实例，jsonFileName 为 JSON 文件名（**尽量和 mockdb 配置文件名保持一致** ）

### service

```javascript
const service = mockdb.service('user.json');
```

#### service.create(model)

创建数据，model 为对象，如果没有 id，则会自动生成 id，返回 model（包含 id）

#### service.batchCreate(models)

批量创建，models 为数组，如果没有 id，则会自动生成 id，返回 models（包含 id）

#### service.delete(id)

根据 id 删除，删除成功返回被删除的数据，否则返回 null

#### service.patch(id, data)

根据 id 补丁更新，返回更新后的对象

#### service.find(id)

根据 id 查找，返回找到的对象

#### service.pagingQuery({ page, size, filter, sort })

分页查询，返回对象，形如`{ data: [...], total: 100 }`

参数列表如下：

- page: 当前页码，默认 1
- size: 每页条数，默认 10
- filter: 过滤方法 filter 的回调函数，Function
- sort: 排序方法 sort 的回调函数，Function

返回值如下：

- data：查询到的数据列表，Array
- total：满足条件的总数据量，Number

#### service.getState()

获取 JSON 文件中的全部数据，返回对象，形如：`{ list: [ ... ], ... }`

#### service.setState(state)

设置 JSON 文件中的全部数据，返回 service 实例

#### service.getDB()

返回 db 实例，具体 API 详见：[lowdb](https://github.com/typicode/lowdb)

---
_Source: https://npm.io/package/@andremao/mockdb · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
