Skip to content

Commit

Permalink
feat(api): 支持自定义response映射关系
Browse files Browse the repository at this point in the history
  • Loading branch information
ly525 committed Jun 27, 2021
1 parent 2ab680c commit 4cc0c37
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 72 deletions.
115 changes: 57 additions & 58 deletions src/actions/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ams from '../ams';
import { getQueryString, getType, isFn } from '../utils';
import { getQueryString, getType, isFn, responseHandler } from '../utils';
import { httpRequestTypeExcludeGet } from '../ams/request';

/**
Expand Down Expand Up @@ -112,19 +112,14 @@ export const read = ams.createApiAction({
};
},
success(res) {
const successCode = this.getConfig('resource.api.read.successCode') || this.getConfig('resource.api.successCode');
if (res.data.code === successCode) {
const config = this.resource.api.read;
if (typeof config === 'object' && typeof config.transform === 'function') {
this.setBlockData(config.transform(res.data.data));
} else if (typeof config === 'object' && typeof config.responseDataParse === 'function') {
this.setBlockData(config.responseDataParse(res.data));
} else {
this.setBlockData(res.data.data);
}
const { message, code, isSuccess, data } = responseHandler.call(this, res, 'read');
if (isSuccess) {
const { transform, responseDataParse } = this.resource.api.read || {};
const handler = transform || responseDataParse || (data => data);
this.setBlockData(handler(data));
} else {
this.$message.error(`${res.data.msg}(${res.data.code})`);
throw '@read:' + res.data.code;
this.$message.error(`${message}(${code})`);
throw '@read:' + code;
}
return res;
}
Expand Down Expand Up @@ -160,16 +155,14 @@ export const update = ams.createApiAction({
};
},
success(res) {
// 默认successCode
const successCode = this.getConfig('resource.api.update.successCode') || this.getConfig('resource.api.successCode');
if (res.data.code === successCode) {
const { message, code, isSuccess } = responseHandler.call(this, res, 'update');
if (isSuccess) {
this.$message.success('更新成功');
if (typeof this.on['update-success'] === 'function') {
this.on['update-success'](res.data);
}
const onSuccess = this.on['update-success'];
if (isFn(onSuccess)) onSuccess(res.data);
} else {
this.$message.error(`${res.data.msg}(${res.data.code})`);
throw '@update:' + res.data.code;
this.$message.error(`${message}(${code})`);
throw '@update:' + code;
}
return res;
}
Expand Down Expand Up @@ -206,16 +199,14 @@ export const deleteAction = ams.createApiAction({
};
},
success(res) {
// 默认successCode
const successCode = this.getConfig('resource.api.delete.successCode') || this.getConfig('resource.api.successCode');
if (res.data.code === successCode) {
const { message, code, isSuccess } = responseHandler.call(this, res, 'delete');
if (isSuccess) {
this.$message.success('删除成功');
if (typeof this.on['delete-success'] === 'function') {
this.on['delete-success'](res.data);
}
const onSuccess = this.on['delete-success'];
if (isFn(onSuccess)) onSuccess(res.data);
} else {
this.$message.error(`${res.data.msg}(${res.data.code})`);
throw '@delete:' + res.data.code;
this.$message.error(`${message}(${code})`);
throw '@delete:' + code;
}
return res;
}
Expand Down Expand Up @@ -245,21 +236,21 @@ export const create = ams.createApiAction({
};
},
success(res) {
// 默认successCode
const successCode = this.getConfig('resource.api.create.successCode') || this.getConfig('resource.api.successCode');
if (res.data.code === successCode) {
const { message, code, isSuccess } = responseHandler.call(this, res, 'create');
if (isSuccess) {
this.$message.success('创建成功');
if (typeof this.on['create-success'] === 'function') {
this.on['create-success'](res.data);
}
const onSuccess = this.on['create-success'];
if (isFn(onSuccess)) onSuccess(res.data);
} else {
this.$message.error(`${res.data.msg}(${res.data.code})`);
throw '@create code:' + res.data.code;
this.$message.error(`${message}(${code})`);
throw '@create code:' + code;
}
return res;
}
});

// https://github.com/vipshop/ams/blob/5c8e0112c3b8e42c4bed9ff658767bbdbcf9bbd4/src/ams/request.js#L162
// createApiAction -> src/ams/request.js
export const list = ams.createApiAction({
getOptions(params) {
// 使用传入页数,如搜索使用 @list:1 将页数重置为1
Expand Down Expand Up @@ -336,37 +327,45 @@ export const list = ams.createApiAction({
params: arg
};
},
/**
*
* @param {*} res { status: statusCode, data: JSON.parse(xhr.responseText) }
*/
success(res) {
// 默认successCode
const successCode = this.getConfig('resource.api.list.successCode') || this.getConfig('resource.api.successCode');
if (
res.data.code === successCode &&
res.data.data
) {
const config = this.resource.api.list;
this.data.total = res.data.data.total;
// whenSuccess = res => res[codePath] === expectedCode
const { message, code, isSuccess, data, getter } = responseHandler.call(this, res, 'list');
if (isSuccess) {
const total = data[getter.totalPath];
const list = data[getter.listPath];
this.data.list = list;
this.data.total = total;

if (typeof config === 'object' && typeof config.transform === 'function') {
this.data.list = config.transform(res.data.data.list) || [];
} else if (typeof config === 'object' && typeof config.responseDataParse === 'function') {
const convertResponseDataParse = config.responseDataParse(res.data);
if (getType(convertResponseDataParse) !== 'object') {
const { transform, responseDataParse } = this.resource.api.list || {};
if (isFn(transform)) {
this.data.list = transform(data);

} else if (isFn(responseDataParse)) {
const parsedData = responseDataParse(data);
if (getType(parsedData) !== 'object') {
console.error('responseDataParse中需要返回object类型,如{ list: [] }');
this.data.list = [];
} else {
this.data = { ...this.data, ...config.responseDataParse(res.data) };
this.data = {
...this.data,
...responseDataParse(data)
};
}
} else {
this.data.list = res.data.data.list || [];
}
if (typeof this.on['list-success'] === 'function') {
this.on['list-success'](res.data);
}
const onSuccess = this.on['list-success'];
if (isFn(onSuccess)) onSuccess(data);
} else {
this.$message.error(`${res.data.msg}(${res.data.code})`);
throw '@list:' + res.data.code;
this.$message.error(`${message}(${code})`);
throw '@list:' + code;
}

return res;
}
});

function defaultResponseDataParse(data) { return data }
function defaultTransform(data) { return data }
24 changes: 10 additions & 14 deletions src/ams/configs/alias/field.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { deepExtend, get } from '../../../utils';
/* eslint-disable complexity,no-new,max-depth */

import { deepExtend, responseHandler } from '../../../utils';
import * as fieldGetSet from '../field-get-set';
import { httpRequestTypeExcludeGet } from '../../request';

Expand Down Expand Up @@ -171,19 +173,13 @@ export const SELECT_REMOTE = {
$field.loading = true;
const res = await remoteConfig.request.call(this, $field, query, isBackfill);
$field.loading = false;

let data = get(res.data, remoteConfig.dataPath);
let successCode;

if (typeof remoteConfig.successCode !== 'undefined') {
successCode = remoteConfig.successCode;
} else {
successCode = this.getConfig('resource.api.successCode');
}
if (
res.data.code === successCode &&
data
) {
// eslint-disable-next-line no-unused-vars
const { isSuccess, data } = responseHandler.call(this, res, '', {
dataPath: remoteConfig.dataPath, // 'data.list',
successCode: remoteConfig.successCode || this.getConfig('resource.api.successCode'),
codePath: remoteConfig.codePath || this.getConfig('resource.api.code') || 'code'
});
if (isSuccess && data) {
const options = remoteConfig.transform.call(this, $field, data);
const optionsEntity = options.reduce((obj, cur) => Object.assign(obj, { [cur.label]: cur.value }), {});
if (remoteConfig.isCache) {
Expand Down
61 changes: 61 additions & 0 deletions src/utils/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { get as lodashGet } from 'lodash';

const defaultGetter = {
codePath: 'code',
successCode: 0,
dataPath: 'data',
totalPath: 'total',
listPath: 'list',
messagePath: 'msg',
};

/**
* 从 API Response 中获取相关字段,如是否成功、total、data 等
* https://github.com/vipshop/ams/pull/125
*
* @param {Object} response : api response data
* @param {String} action : read/update/list/delete 增删改查
* @param {Object} actionGetter : 适配更多接口的返回值
*
* ams 默认接口数据结构: https://vipshop.github.io/ams/api/api.html#%E9%80%9A%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84
*
* -------常规请求----------
* {
[codePath]: [successCode],
[dataPath]: String,
[messagePath]: String
* }
*
*
* ------- 列表请求----------
* {
[codePath]: [successCode],
[dataPath]: {
[dataPath.listPath]: [],
[dataPath.totalPath]: Number,
},
[messagePath]: String
* }
*
*
*/
export function responseHandler(response, action, actionGetter) {
const configGetter = this.getConfig(`resource.api.${action}.getter`);
const getter = {
...defaultGetter,
...actionGetter,
...configGetter
};

const code = lodashGet(response.data, getter.codePath); // api response(success/result)对应的值
// eslint-disable-next-line
const isSuccess = code == getter.successCode;
return {
code,
getter,
isSuccess,
data: lodashGet(response.data, getter.dataPath),
total: lodashGet(response.data, getter.totalPath),
message: lodashGet(response.data, getter.messagePath),
};
}
1 change: 1 addition & 0 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './dom';
export * from './function';
export * from './tools';
export * from './localstorage';
export * from './api';

export function get(object, path) {
path = path.split('.');
Expand Down

0 comments on commit 4cc0c37

Please sign in to comment.