Skip to content

结合数据生成工具

本章将会教你如何结合数据生成工具来封装自定义装饰器,让你的代码更加简洁而优雅,并结合数据生成工具完成业务mock

准备项目结构

bash
project
 ├── api
   ├── common
   └── index.ts      # 通用接口装饰器
   └── userApi.ts        # 真实接口类
 └── mock
     ├── common
   └── index.ts      # 通用方法
     ├── models
   └── userModel.ts  # 定义数据模型
     └── userMock.ts       # 封装用户mock装饰器

定义数据模型

这里数据模型通过data-faker-plus来定义,在/mock/models/userModel.ts

ts
import { DataField, DataModel, defineModel, faker } from 'data-faker-plus';

// 定义用户数据模型
@DataModel('user')
export class UserModel {
  @DataField('string.uuid')
  declare id: string;
  @DataField('person.firstName')
  declare firstName: string;
  @DataField('person.lastName')
  declare lastName: string;
  @DataField(['number.int', { min: 1, max: 120 }])
  declare age: number;
  @DataField(ctx => {
    return faker.internet.email({ firstName: ctx.firstName, lastName: ctx.lastName });
  })
  declare email: string;
  @DataField('phone.number')
  declare phone: string;
  @DataField('person.sex')
  declare sex: string;
}

data-faker-plus

这里我推荐大家使用data-faker-plus来完成数据模拟。有关data-faker-plus的使用方法,请参考

  1. npm
  2. github
  3. 中文官网
  4. 英文官网

封装 mock 装饰器

定义通用方法

/mock/common/index.ts,在这里面定义了通用错误处理方法

ts
/**
 * 公共方法
 */

import { HttpResponse } from 'msw';

/**
 * 网络错误
 * @returns
 */
export function netWorkError() {
  return HttpResponse.error();
}

定义用户 mock 装饰器

/mock/userMock.ts,在这里面定义了用户相关的mock装饰器

ts
import { HttpResponse, Mock, MockHandlers } from '@/index';
import { fakeData, useModel } from 'data-faker-plus';
import { UserModel } from './models/userModel';
import { netWorkError } from './common';

// 使用data-faker-plus生成假数据
const users = fakeData(useModel(UserModel), 30);
/**
 * 模拟用户页面
 */
export function MockUserPages() {
  let handlers = {
    default: () => {
      return HttpResponse.json({
        message: 'success',
        data: users,
      });
    },
    error: netWorkError,
  };
  return Mock(handlers);
}

/**
 * 模拟删除用户
 */
export function MockUserDelete() {
  let handlers: MockHandlers = {
    default: ({ params }) => {
      // 获取用户参数
      const { id } = params;
      // 找到用户
      const user = users.find((item: any) => item.id === id);
      // 删除用户
      users.splice(users.indexOf(user), 1);
      // 返回成功信息
      return HttpResponse.json({
        message: 'delete success',
      });
    },
    error: netWorkError,
  };
  return Mock(handlers);
}

/**
 * 模拟更新用户
 */
export function MockUserUpdate() {
  // 成功时的方法
  const success: MockHandlers = async ({ request }) => {
    // 获取请求体参数
    let user = await request.json();
    user = JSON.parse(JSON.stringify(user)) as UserModel;

    if (!user || !user.id) {
      return HttpResponse.json({
        status: 400,
        message: 'params error',
      });
    }
    // 更新用户信息
    const index = users.findIndex((item: any) => item.id === user.id);
    users[index] = user;
    return HttpResponse.json({
      message: 'update success',
    });
  };
  // 失败时的方法
  const error = netWorkError;
  // 返回 Mock 装饰器
  return Mock({
    default: success,
    error,
  });
}

/**
 * 添加用户
 */
export function MockUserCreate() {
  // 成功时的方法
  const success: MockHandlers = async ({ request }) => {
    // 获取请求体参数
    let user = await request.json();
    // 新增用户
    users.unshift(user);
    return HttpResponse.json({
      message: 'create success',
    });
  };
  // 失败时的方法
  const error = netWorkError;
  // 返回 Mock 装饰器
  return Mock({
    default: success,
    error,
  });
}

封装接口装饰器

/api/common/index.ts

ts
import { HttpMethodDecoratorConfig, Post } from '@/index';

/**
 * 分页查询装饰器
 * @param config 请求配置
 * @returns post装饰器
 */
export function Pages(config: HttpMethodDecoratorConfig) {
  config.headers = {
    'Content-Type': 'application/json',
  };
  return Post(config);
}

定义真实接口类

/api/userApi.ts

ts
import { Delete, Get, Post, Put } from '@/core/httpMethod';
import { HttpApi } from '@/core/ioc';
import { Pages } from './common';
import { BodyParam, PathParam } from '@/core/params';
import { MockUserCreate, MockUserDelete, MockUserPages, MockUserUpdate } from '../mock/userMock';

@HttpApi({
  baseURL: 'http://localhost:3000/api/users',
  mock: {
    on: true,
    condition: () => {
      return process.env.NODE_ENV === 'test';
    },
  },
})
class UserApi {
  /**
   * 用户分页查询接口
   * @param page 页号
   * @param size 每页数量
   */
  @Pages({ url: '/pages/:page/:size' })
  @MockUserPages()
  getUserPages(@PathParam('page') page: number, @PathParam('size') size: number): any {}

  /**
   * 删除用户接口
   * @param id 用户ID
   */
  @Delete('/:id')
  @MockUserDelete()
  deleteUser(@PathParam('id') id: number): any {}

  /**
   * 添加用户接口
   */
  @Post('/')
  @MockUserCreate()
  addUser(@BodyParam() user: { name: string; age: number }): any {}

  /**
   * 更新用户接口
   */
  @Put('/')
  @MockUserUpdate()
  updateUser(@BodyParam() user: { id: number; name: string; age: number }): any {}
}

export const userApi = new UserApi();

调用接口测试

打开mock开关,测试接口是否正常工作

ts
// 一定要先开启mock开关
MockAPI.on();
const { data } = await userApi.getUserPages(1, 10)();
console.log(data);
// 删除用户
const { data: data2 } = await userApi.deleteUser(1)();
console.log(data2);
// 新增用户
const { data: data3 } = await userApi.addUser({ name: 'test', age: 18 })();
console.log(data3);