npm package: @flatjs/mock
Description: ## @flatjs/mock 使用指南
Latest version: 2.4.2

# @flatjs/mock

## @flatjs/mock 使用指南

迅速启动本地 Mock 服务、方便快捷的模拟各种接口请求场景、模拟各种数据类型响应;

备注 1: 建议保持 Mock 数据的拟真性, 如图片尺寸、文字长短、姓名、日期、证件号码等等, 能提升理解度、美观度、也能发现 UI 的兼容性问题。
备注 2: Postman Collection: https://www.getpostman.com/collections/ae53e4a38a9de2e44b6a

### Step1: 准备工作

1. 安装 VsCode https://code.visualstudio.com;
2. 打开 VsCode, 左侧菜单选择「 Extensions 」, 查找并安装 VsCode 插件: `ESLint`, `Prettier - Code formatter`;
3. 学习 mock 数据的生成规则, 需要 VPN : https://github.com/nuysoft/Mock/wiki/Getting-Started;

### Step2: 配置本地 hosts 文件, 目录: /etc/hosts

1. `127.0.0.1 localhost dev.flatjs.com`

### Step3: 安装依赖 & 启动服务

1. `npm install -g @flatjs/cli yarn`
2. `yarn`
3. `flat mock`

### 静态文件资源

| 地址                                           |
| ---------------------------------------------- |
| http://dev.flatjs.com:40000/static/example.png |
| http://dev.flatjs.com:40000/static/banner.png  |
| http://dev.flatjs.com:40000/static/icon.png    |

### Rest & Rest-nest

| 接口名              | 接口地址                                                                                |
| ------------------- | --------------------------------------------------------------------------------------- |
| 获取产品列表        | http://dev.flatjs.com:40000/api/rest/queryProductList?page=1&pageSize=10                |
| 获取用户信息        | http://dev.flatjs.com:40000/api/rest/queryUserinfo                                      |
| 获取订单列表        | http://dev.flatjs.com:40000/api/rest/queryOrderList?page=1&pageSize=10                  |
| 获取订单详情        | http://dev.flatjs.com:40000/api/rest/queryOrderDetail?orderNo=1                         |
| 支付订单            | http://dev.flatjs.com:40000/api/rest/payOrder?orderNo=1                                 |
| 图片上传            | http://dev.flatjs.com:40000/static/upload-files.png                                     |
| 获取图片流          | http://dev.flatjs.com:40000/api/rest/showImage?fileKey=idcardEmblem                     |
| 模拟各种状态码, 500 | http://dev.flatjs.com:40000/api/rest/fake-500                                           |
| 登录 (nest)         | http://dev.flatjs.com:40000/api/rest/login/loginByUsername?username=abc&password=123456 |

### Func-simple & Func-simple-nest

| 接口名              | 接口地址                                                |
| ------------------- | ------------------------------------------------------- |
| 获取产品类目        | http://dev.flatjs.com:40000/static/func-simple.png      |
| 获取产品类目 (nest) | http://dev.flatjs.com:40000/static/func-simple-nest.png |

```json
// 请求体 Request
{
  "protocol": {
    "functionCode": "queryProductList",
    "fromPlatform": "tc_app",
    "userId": "785d680efb8515c71715a694fa0afe81"
  },
  "param": {
    "page": 1,
    "pageSize": 10
  }
}
```

```json
// 响应体 Response
{
  "code": "0000",
  "message": "success",
  "data": {}
}
```

### Others（任意未预先匹配的路径）

| 接口名  | 接口地址                              |
| ------- | ------------------------------------- |
| unknown | http://dev.flatjs.com:40000/api/a/b/c |

### Proxy (代理)

| 接口名 | 接口地址                                             |
| ------ | ---------------------------------------------------- |
| proxy  | http://dev.flatjs.com:40000/proxy/rest/queryUserinfo |

### gql

| 接口名 | 接口地址                                   |
| ------ | ------------------------------------------ |
| gql    | http://dev.flatjs.com:40000/static/gql.png |

## The usages

```sh
npm i @flatjs/mock
```

```sh
// Install the following devDependencies.
"@types/express": "^4.17.7",
"@types/express-mung": "^0.5.2",
"@types/http-proxy-middleware": "^0.19.3",
"@types/mockjs": "^1.0.3",
```

The configuration of the `flatjs.mock.js` as below example

```ts
baseCwd: join(process.cwd(), `packages/mock/mocks`),
apiContext: '/api',
hostname: 'dev.flatjs.com',
port: 4000,
staticMap: {
  '/static': 'static',
},
mockMap: {
  '/func': { type: 'FUNC', defs: ['func'], middlewares: {res: otherFuncMiddleware.forFuncApiSimpleResponse()] } },
  '/rest': { type: 'REST', defs: ['rest']},
},
```

```ts
// Tor expressjs middleware cycle
// The outer middlewares defined by user should be executed in the final phase

// e.g. Below middleware will used to simplify response for `func`
otherRestMiddleware.forFuncApiSimpleResponse();
```

## Features

- Both support .ts ,.js mock services.
- Provider class `MockBase` as base class for all mock services
- Built in support `mockjs`
- Proiders usually module `exports`.

## Examples

- The first scenario, auto instance class need `@Mockable()` for class

```ts
@mockable()
export default class MockProductService extends MockBase {
  @mockAlias('products')
  geProducts(_req: MockRequest, res: MockResponse): void {
    res.json({
      code: '0000',
      message: 'func product',
      data: ['https://www.flatjs.com/blog/img/flatjs_avatar.png'],
    });
  }
}
```

- The second scenario, auto instance class need `@Mockable()` for class

```ts
@mockable()
export class MockCatalogService extends MockBase {
  @mockAlias('catalog/list')
  getCatalogs(_req: MockRequest, res: MockResponse): void {
    res.json({
      code: '0000',
      message: 'func catalogs',
      data: ['https://www.flatjs.com/blog/img/flatjs_avatar.png'],
    });
  }
}
```

- The third scenario, use module.exports = new () the class decortor `@Mockable` is optional

```ts
class MockUserService extends MockBase {
  @mockAlias('product/list')
  getUsers(_req: MockRequest, res: MockResponse): void {
    res.json({
      data: ['https://www.flatjs.com/blog/img/flatjs_avatar.png'],
    });
  }
}
module.exports = new MockUserService();
```

- The forth scenario

```ts
export function getAds(_req: MockRequest, res: MockResponse): void {
  res.json({
    code: '0000',
    message: 'func ads',
    data: ['https://www.flatjs.com/blog/img/flatjs_avatar.png'],
  });
}
```

## Use Http Proxy `proxyMap`

```ts
 ....
  proxyMap: {
    '/proxy': {
      target: 'https://fex.qa.tcshuke.com',
      pathRewrite: { '^/proxy': '' },
      router(req) {
        switch (req.query.env) {
          case 'me':
            return 'https://dev.flatjs.com:4000';
          case 'uat':
            return `https://fex.qa.tcshuke.com`;
        }
        return 'https://fex.qa.tcshuke.com';
      },
    },
  },
  // request `/proxy/mock/api/status/200?env=uat` ---> `https://fex.qa.tcshuke.com/mock/api/status/200?env=uat`
```

## Use multer for file upload

```ts
import { mockAlias, MockBase, MockRequest, MockResponse } from '@flatjs/mock';
import fs from 'fs';
import mimeTypes from 'mime-types';
import multer from 'multer';
import { join } from 'path';

const storage = multer.diskStorage({
  destination: function (_req, _file, cb) {
    fs.mkdirSync(join(__dirname, '../static/uploads'), { recursive: true });
    cb(null, join(__dirname, '../static/uploads'));
  },
  filename: function (_req, file, cb) {
    const { mimetype, fieldname } = file || {};
    const extension = mimeTypes.extension(mimetype) as string;
    cb(null, `${fieldname}-${Date.now()}.${extension}`);
  },
});

class MockService extends MockBase {
  @mockAlias('/uploadFile')
  uploadFile(req: MockRequest, res: MockResponse): void {
    const upload = multer({
      storage,
    }).any();

    upload(req, res, () => {
      const files = (req.files as Express.Multer.File[]) || [];
      res.json({
        code: '0000',
        message: 'upload files',
        data: {
          ...req.body,
          fieldnames: files.map(
            (s) => `${this.$hostUri(req)}/static/uploads/${s.filename}`
          ),
        },
      });
    });
  }
}

module.exports = new MockService();
```

## Notes

Note, it we want to using `import` or `require` with `cache`
First we can't include this folder into `mockMap` of `flatjs.mock.js`
Second we can't use importFresh(``)
@example

```ts
mockMap: {
  '/func': { type: 'FUNC', defs: ['func'], middlewares: {} },
  '/rest': { type: 'REST', defs: ['rest'], middlewares: {} },
},
the `defs` config should not include any `folders` that we want to cache.
```