anymock-openapi

<p align="center"> <a href="https://anymock.alipay.com/"> <img width="25%" src="https://gw.alipayobjects.com/mdn/rms_2a4b50/afts/img/A*HUcOR5hvy-cAAAAAAAAAAABkARQnAQ" alt="Anymock"> </a> </p>

Usage no npm install needed!

<script type="module">
  import anymockOpenapi from 'https://cdn.skypack.dev/anymock-openapi';
</script>

README

anymock-openapi

Anymock

可跨端的 Anymock Openapi SDK。可用于获取 Mock 数据以及其他众多 openapi。

—— 一款好用的 Anymock 平台 辅助工具

Install

tnpm install anymock-openapi --save

Concept

通过调用者使用不同环境下的的请求发生器,该 openapi sdk 可以灵活适配浏览器或 Node.js 场景。

请求发生器在本 SDK 中被抽象成“管道”,英文名 pipe。

Use

Browser

import AnymockOpenapi from 'anymock-openapi';
import { EClients, ETypes } from 'anymock-include';

const fetch = window.fetch;
const config = {
  fromClient: EClients.chromeExtensionAnymock,

  // 请前往 https://anymock.alipay.com/ 获取项目 token
  projectToken: 'YOUR_ANYMOCK_PROJECT_TOKEN',
};

/**
 * Pipe for browser.
 * @params {IRequestOptions} options
 * @return Promise<any>
 */
const pipe = (options) => {
  // interface IRequestOptions {
  //   url: string;
  //   headers: { [key: string]: any };
  //   method: string;
  //   data: { [key: string]: any }
  // }

  const url = options.url;
  const body = JSON.stringify(options.data);

  delete options.url;
  delete options.data;

  return fetch(url, { ...options, body })
    .then(res => res.json());
};

const openapi = new AnymockOpenapi(config, pipe);

main();

async function main() {
  // 1. fetch mock data
  const resp = await openapi.mock.query({
    type: ETypes.HTTP,
    subType: 'POST',
    matching: '/post',
    // parameters: {},
  });

  console.log('mock resp from https://anymock.alipay.com:\n', resp);
  console.log();
  console.log('mock data:')
  console.log(resp.data.mock.data);
  console.log();
  console.log('typeof mock data:', typeof resp.data.mock.data);

  // 2. fetch project details
  const { data: projectDetails } = await openapi.project.get();

  // projectDetails interface
  // {
  //   id: string;
  //   name: string;
  //   cname: string;
  //   // ...
  // }
}

Node.js

Playground: https://runkit.com/embed/qaym3apxzvma

const fetch = require('node-fetch');
const AnymockOpenapi = require('anymock-openapi').default;
const { EClients, ETypes } =  require('anymock-include');

const config = {
  fromClient: EClients.nodejsAnymock,

  // 请前往 https://anymock.alipay.com/ 获取项目 token
  projectToken: 'YOUR_ANYMOCK_PROJECT_TOKEN',
};

/**
 * Pipe for Node.js.
 * @params {IRequestOptions} options
 * @return Promise<T>
 */
const pipe = (options) => {
  // interface IRequestOptions {
  //   url: string;
  //   headers: { [key: string]: any };
  //   method: string;
  //   data: { [key: string]: any }
  // }

  const url = options.url;
  const body = JSON.stringify(options.data);

  delete options.url;
  delete options.data;

  return fetch(url, { ...options,body })
    .then(res => res.json());
};

const openapi = new AnymockOpenapi(config, pipe);

main();

async function main() {
  const resp = await openapi.mock.query({
    type: ETypes.HTTP,
    subType: 'POST',
    matching: '/post',
  });

  console.log('mock resp from https://anymock.alipay.com:\n', resp);
  console.log();
  console.log('mock data:')
  console.log(resp.data.mock.data);
  console.log();
  console.log('typeof mock data:', typeof resp.data.mock.data);
}

openapi

所有 openapi 方法返回值类型均遵循:

interface IAnymockResponse<T = null> {
  success: boolean;
  data: T;

  errorMessage: string;
  errorCode: string;
  errorExtra: any;
}

公共类型:

// import { IAnymockConfigUpdate } from 'anymock-include';

export interface IAnymockConfigUpdate {
  /**
   * 用户是否自定义请求 mock 数据的 host
   * 默认 https://anymock.alipay.com。注意无结尾斜杠“/”
   */
  host?: string;
  /**
   * 用户 token
   */
  userToken?: string;

  /**
   * 项目 token
   * 必选
   * 请前往 https://anymock.alipay.com/ 获取
   */
  projectToken?: string;

  /**
   * 请求来源
   */
  fromClient?: EClients | string;
}

Mock 数据

获取 Mock 数据

方法:openapi.mock.query({ payload: IMockQueryPayload, options?: IAnymockConfigUpdate })

入参:

// import { IMockQueryPayload } from 'anymock-include';

export interface IMockQueryPayload {
  type: ETypes;

  /** 如果是 type 是 HTTP,则 subType 可以是 GET POST 等 */
  subType?: string;
  matching: string;

  /** 场景 ID。指定返回某个场景下的数据 */
  sceneId?: string;
  parameters?: any;
}

export enum ETypes {
  HTTP = 'HTTP',
  MTOP = 'MTOP',
  JSAPI = 'JSAPI',
}

返回值:Promise<IAnymockResponse<IMockResp>>

export interface IMockResp {
  mock: {
    data: string;
  };
}

示例:

const resp = await openapi.mock.query({
  type: ETypes.HTTP,
  subType: 'GET',
  matching: '/api/projects',
  // parameters: {},
});
更新 Mock 数据

方法:openapi.mock.update(requestId: ID, mockId: ID, payload: Partial<IMock>, config?: IAnymockConfigUpdate)

入参:

export type ID = string | number;

export interface IMock {
  data: string;
  dataType: number;
  gmtCreate: string;
  gmtModified: string;
  id: number;
  mockType: MockTypeEnum;
  requestId: number;
}

返回值:Promise<IAnymockResponse<any>>

示例:

const resp = await openapi.mock.update({
  requestId: 1001,
  mockId: 2001,
  payload: {
    data: '{ success: false, name: "anymock" }'
  },
});

项目

获取项目详情

方法:openapi.project.get(options?: IAnymockConfigUpdate, payload: IGetProjectPayload = {})

入参:可选

返回值:Promise<IAnymockResponse<IProject>>

export interface IProject {
  id: number;
  gmtCreate: string;
  gmtModified: string;
  name: string;
  cname: string;
  avatar?: any;
  description: string;
  spaceId: number;
  status: number;
  token: string;
  members: IMember[];
}

export interface IMember {
  id: number;
  anymockId: string;
  userId: string;
  userName: string;
  nickName: string;
  avatar: string;
}

示例:

openapi.project.get()

接口

获取接口列表

方法:openapi.interface.list(options?: IAnymockConfigUpdate, payload?: IQuery = {})

入参:可选

export interface IQuery {
  [key: string]: any;
}

返回值:Promise<IAnymockResponse<IInterface[]>>

export interface IInterface {
  cname?: any;
  description?: any;
  gmtCreate: string;
  gmtModified: string;
  id: number;
  matching: string;
  matchingType: string;
  name: string;
  projectId: number;
  request: IRequest[];
  subType: string;
  type: string;
}
export interface IRequest {
  cname: string;
  gmtCreate: string;
  gmtModified: string;
  id: number;
  interfaceId: number;
  isActive: boolean;
  mock: IMock[];
  status: number;
}

export interface IMock {
  data: string;
  dataType: number;
  gmtCreate: string;
  gmtModified: string;
  id: number;
  mockType: MockTypeEnum;
  requestId: number;
}

export enum MockTypeEnum {
  ResponseBody = 1,
  ResponseHeader = 2,
  RequestBody = 3,
  RequestHeader = 4,
}
新增接口

方法:openapi.interface.create(payload: IInterfaceModifiableParams, options?: IAnymockConfigUpdate)

入参:必须

export interface IInterfaceModifiableParams {
  type: string;

  /** 若 HTTP 接口则该字段必须 */
  subType?: string;

  matching: string;
  name?: string;
  description?: string;
}

返回值:Promise<IAnymockResponse<number>> 返回新增接口的 id

示例:

openapi.interface.create({
  type: ETypes.HTTP,
  subType: 'GET',
  matching: '/api/projects/:pid',
})
获取接口详情

方法:openapi.interface.get(interfaceId?: string | number, config?: IAnymockConfigUpdate)

入参:接口 id

返回值:Promise<IAnymockResponse<IInterface>>

// 已有,省略

示例:

openapi.interface.get(10001)
更新接口

方法:openapi.interface.update(interfaceId: ID, payload: IInterfaceModifiableParams, config?: IAnymockConfigUpdate)

入参:必须

export interface IQuery {
  [key: string]: any;
}

返回值:Promise<IAnymockResponse<null>>

示例:

openapi.interface.update(1001, { matching: '/api/projects/:pid/interfaces' })
删除接口

方法:openapi.interface.delete(interfaceId: ID, config?: IAnymockConfigUpdate)

入参:必须

返回值:Promise<IAnymockResponse<null>>

示例:

openapi.interface.update(1001)

请求

创建请求(有明确的 interfaceId)

方法:openapi.request.create(interfaceId: ID, payload: Partial<IRequest>, config?: IAnymockConfigUpdate)

入参:必须

返回值:Promise<IAnymockResponse<object>>

示例:

openapi.request.create(1001, {
  cname: '成功'
})
获取请求详情

方法:openapi.request.get(requestId: ID, config?: IAnymockConfigUpdate)

入参:必须

返回值:Promise<IAnymockResponse<IRequest>>

示例:

openapi.request.get(2001)
更新请求

方法:openapi.request.update(interfaceId: ID, requestId: ID, payload: Partial<IRequest>, config?: IAnymockConfigUpdate)

入参:必须

返回值:Promise<IAnymockResponse<object>>

示例:

openapi.request.update(1001, 2001, {
  cname: '失败'
})
删除请求

方法:openapi.request.delete(requestId: ID, config?: IAnymockConfigUpdate)

入参:必须

返回值:Promise<IAnymockResponse<null>>

示例:

openapi.request.delete(2001)
新增请求(可能存在 interfaceId)

复合接口,有可能会先创建一个接口。

当接口存在则在接口下创建一个 request,否则先创建接口然后在其下新增一个 request

定位接口是否存在的规则:优先通过 interfaceId 或通过三要素(type / subType / matching)

方法:openapi.request.addRequest(payload: IAddRequestParam, config?: IAnymockConfigUpdate)

入参:必须

export interface IAddRequestParam {
  /**
   * 若有则通过 interfaceId 唯一定位一个 interface
   * 否则通过三要素唯一定位(性能相对较差,但是为了客户端方便)
   */
  interfaceId?: ID;


  // 这些属性来自 interface
  // 三要素
  type: string;
  subType: string;
  matching: string;

  description?: string;
  name?: string;


  // 这才是 request 的真正属性
  request: {
    cname: string;
    mock: { data: string };
  };
}

返回值:Promise<IAnymockResponse<{ interface: { id: ID }; request: any }>>

示例:

// 如果 type subType matching 相同的接口存在,则在该接口下新增一个 request
// 否则先创建接口,然后在其下新增一个 request
openapi.request.addRequest({
  type: 'HTTP',
  subType: 'POST',
  matching: '/api/projects/:pid',

  request: {
    cname: '成功',
    mock: {
      data: "{ success: true, name: 'anymock' }"
    }
  }
});

场景

获取场景列表

方法:openapi.scene.list(options?: IAnymockConfigUpdate, payload?: IQuery = {})

入参:可选

返回值:Promise<IAnymockResponse<IScene[]>>

export interface IScene extends Omit<ISceneDBProps, 'id' | 'projectId' | 'status'> {
  /** 场景 id */
  id: string,
  /** 所属项目 id */
  projectId: string,
  name: string,
  description: string;
  active: boolean;
  records: ISceneRecord[];
  sceneUser: ISceneUser,
}

interface ISceneRecord extends IBaseDBProps {
  id: string;
  sceneId: string;
  interface: IInterface;
}

type ISceneUser = ISceneUserDB;

interface ISceneUserDB extends IBaseDBProps {
  id: number;
  sceneId: number;
  userId: number;
  interfaceId: number;
  status: number;
}

interface IBaseDBProps {
  gmtCreate: string;
  gmtModified: string;
}

示例:

const resp = await openapi.scene.list();

Develop

UT

ANYMOCK_HOST=http://127.0.0.1:7002 yarn test packages/openapi/__tests__/scene.spec.ts

yarn test packages/openapi/__tests__/basic.spec.ts