Skip to main content
Version: 4.0.2

使用 API

和后端交互是非常常见的,Godzilla UI 封装网络请求的 API,所有 ajax 都需要通过 API 这个类来发起调用,api 的风格采用 restful api(参考:http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html)

一、 使用 get/post/delete/put 方法

1. 初始化 API 实例

// 引入API组件
import { API } from "@gza/quantex-utils";

class Store {
// this.api = new API('auth'); // 不要这样初始化
constructor() {
// 初始化api实例,传入服务名称(一个服务名称可以映射到后端的真实服务)
// 注意,这个初始化一般要放在构造函数中(或者具体方法中),不能作为实例属性
this.api = new API("auth");
}
}

2. 调用后端服务

class Store {
constructor() {
this.api = new API("auth");
}
// GET方法,一般用来获取信息,不涉及新增、修改、删除数据的操作
fetchUserInfo = userCode => {
let params = {
code: userCode
};
// 其中url中的{code}会被params中的code属性值替换,并发起get请求
// 返回一个promise
return this.api.get("api/v2/users/{code}", params);
};
// POST方法,一般用来提交表单数据
login = params => {
// 所有的post请求,都会默认带loading效果,如果不想要,可以通过第三个参数关闭
// return this.api.post('api/v2/users/login', params, {loading: false});
return this.api.post("api/v2/users/login", params);
};
// PUT方法,一般用来修改表单数据
updateUserInfo = () => {
return this.api.put("api/v2/users/{code}", params);
};
}

一般与服务端的交互都会写在 Store 这一层,集中管理,强烈不建议放在组件层(组件只负责渲染,不负责处理业务逻辑)

3. 处理返回结果

import Store from "./Store";
class LoginComponent extends Component {
store = new Store();
login = () => {
let params = {};
this.store.login(params).then(res => {
if (res.code === 200) {
// 200是正常的返回码
// 处理登录成功逻辑
} else {
// 处理失败逻辑,失败了一般需要弹出框提示,一般调用组件Alert提供的静态方法error,传入整一个response对象
Alert.error(res);
}
});
};
}

二、 使用 list/query 方法

除了提供 get/post/delete/put 方法外,还提供了另外两个专用方法,list 和 query 方法,这是结合通用查询的方法,会跟服务端约定好数据格式

class Store {
constructor() {
this.api = new API("auth");
}
// list,查询满足条件的所有数据
getAllUser = params => {
this.api.list("/api/v2/users/list", params);
};
// query是分页接口
queryUser = params => {
this.api.query("/api/v2/users/query", params);
};
}

三、 使用 easyApi 方法

使用 easyApi 相关方法,默认由框架弹窗显示错误,并且成功的返回值由原来的 res 改为 res.data,开发人员仅需要关注成功返回的执行逻辑。

1. easyPost 的使用

class Store {
constructor() {
this.api = new Api("auth");
}
addRole = formData => {
return this.api.easyPost("/api/v2/roles", formData);
};
}
class RoleComponent {
// 采用async/await
handleAddRole = async () => {
let res = await this.store.addRole(formData);
// 关闭弹出框和刷新,如果上一步报错了,就不会执行如下两个方法了
this.search();
this.modal.close();
};
}

2. 其他API

  • easyGet
  • easyPost
  • easyPut
  • easyDelete
  • easyList

参数传递同之前 Api

参数说明类型默认值
url请求地址string-
params请求参数object-
config配置object-

处理正确返回,入参为 res.data

resolve(res.data)

四、 使用 adaptor

在某些场景下, 需要在请求发起时做一些判断, 从而拦截某些请求或者对返回数据做一些处理, 比如字典缓存. 需要注意的是, setAdaptor 之后, 所有 new API() 请求都会走 adaptor 函数, adaptor 只允许设置一个函数, 重复 setAdaptor 会覆盖之前的函数.

import { API } from "@gaz/quantex-utils";

const runConfQTUtil = () => {
const dictCache = new Map();

// request: Request对象, 包含 { method, url, headers, body } 等参数
// params: api实例 get/post/put/delete 请求发起时传入的params(第二个参数)
// adaptor 函数必须返回 Promise
API.setAdaptor(({ request, params }) => {
// 如果请求地址包含 /Roles/dict (用户角色字典请求) , 会去字典缓存(dictCache) 中查找
if (
request.url.includes("/Roles/dict") &&
params.dictKey &&
dictCache.get(params.dictKey)
) {
// 获取到缓存数据时, 直接返回缓存的值
// 限定 { ok , json } 格式, 这个对象会返回给 api 实例中, 进行后续的数据处理, 比如 logger 等
const cacheData = dictCache.get(params.dictKey);
return Promise.resolve({
ok: true,
json: () => cacheData
});
}

// 如果 缓存中 没有找到, 就发起请求
// 注意: adaptor函数中不允许使用 new API(), 需要用原生的 fetch
return fetch(request).then(async res => {
if (res.ok) {
// 在数据返回成功时, 可以对数据作 自定义的处理, 比如缓存字典
// 注意: res.json 方法只允许使用一次, 所以在 .json 之前必须使用 clone(), 因为 API 实例内部也需要 json() 处理
await res
.clone()
.json()
.then(result => {
if (
request.url.includes("/Roles/dict") &&
params.dictKey &&
result.code === 200
) {
// 对返回的字典数据进行缓存, 以 dictKey 作为 Map's key
dictCache.set(params.dictKey, result);
}
});
}
// API 实例内部仍然会对 res 作处理, 所以需要返回 res(Response对象)
return res;
});
});
};

export default runConfQTUtil;

// other file , ex: app/index.js
import runConfQTUtil from "./runConfQTUtil";
runConfQTUtil(); // 执行方法从而设置一个API全局的 adaptor
// api 请求中也允许使用 adaptor 来覆盖全局的 adaptor
import React from 'react';
import { API } from '@gza/quantex-utils';

class Comp extends React.component {
api = new API('auth');

component() {
this.doRequest();
}

doRequest() {
this.api.get('/Roles/dict', { dictKey: 'id_name' }, { adaptor: ({ request, params }) => {
return Promise.resolve({
ok: true,
json: () => {
code: 200,
msg: 'Data from adaptor',
data: {}
}
})
} }).then(res => {
// 打印 res: { code: 200, msg: 'Data from adaptor', data: {} }
console.log(res);
});
}
}

五、 config 具体属性

所有的 api 方法都会提供一个 config 配置参数,具体定义如下

参数说明类型默认值
loading数据未加载到时是否展示 Spin 组件booleantrue(get 请求默认为 false)
timeout设置超时: timeout == -1 时,接口永不超时。timeout != -1 按照设置的时间string |number-
multipart设置为 true 时为富文本上传boolean-
transformResponse在传递给 then/catch 前,允许修改响应数据(res) => res-
adaptor可以拦截请求, 根据需求作自定义操作({request: Request, params: any}) => Promise<any>-