mux-fetch
Version:
356 lines (304 loc) • 9.07 kB
JavaScript
/*!
* mux-fetch.js v0.0.1-alpha.15
* (c) 2018-2019 空鱼
* Released under the MIT License.
*/
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var muxLib = require('mux-lib');
var defaultFetch = _interopDefault(require('isomorphic-fetch'));
function compose(...funcs) {
if (funcs.length === 0) {
return muxLib.returnSelf;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => b(a(...args)));
}
// 处理get的JSON数据
const normalizeParams = (obj, prefix = "?") => Object.entries(obj).reduce((p, [key, value]) => `${p}${key}=${encodeURIComponent(value ? value : "")}&`, prefix); // 处理formData的数据
const normalizeFormDataParams = params => {
const myFormData = new FormData();
Object.keys(params).forEach(key => {
myFormData.append(key, params[key]);
});
return myFormData;
}; // 生成一个get的url
const normalize = (url, params = {}, prefix) => {
return url + normalizeParams(params, prefix);
};
const checkGlobalConfig = config => {
// prefix 只能为 undefined 和 string
if (config.prefix !== undefined) {
muxLib.invariant(muxLib.isString(config.prefix), `[fetch] prefix should be string , but got ${typeof config.prefix}`);
} // fetchOption 只能为 undefined 和 object
if (config.fetchOption) {
muxLib.invariant(muxLib.isPlainObject(config.fetchOption), `[fetch] fetchOption should be plain object , but got ${typeof config.fetchOption}`);
} // responseHandle 只能为 undefined 和 function
if (config.responseHandle) {
muxLib.invariant(muxLib.isFunction(config.responseHandle), `[fetch] responseHandle should be function , but got ${typeof config.prefix}`);
} // interceptor 只能为 undefined 和 object
if (config.interceptor) {
muxLib.invariant(muxLib.isPlainObject(config.interceptor), `[fetch] interceptor should be plain object , but got ${typeof config.interceptor}`); // 每一种的 interceptor 只能为 undefined 和 Array<Function>
Object.keys(config.interceptor).forEach(key => {
if (config.interceptor[key]) {
muxLib.invariant(muxLib.isArray(config.interceptor[key]), `[fetch] each interceptor should be array , but got ${typeof config.interceptor[key]}`);
config.interceptor[key].forEach(v => {
muxLib.invariant(muxLib.isFunction(v), `[fetch] each interceptor should be Array<Function> , but got ${typeof v}`);
});
}
});
}
};
const configFactory = (config, base = globalConfigMap.get("config") || DEFAULT_CONFIG) => {
// 合并 prefix
const prefix = config.prefix || base.prefix; // 合并 responseHandle
const responseHandle = config.responseHandle || base.responseHandle; // 合并 fetchOption
const fetchOption = Object.assign({}, base.fetchOption || {}, config.fetchOption || {}); // 合并 interceptor
const interceptor = Object.keys(DEFAULT_CONFIG.interceptor).reduce((p, key) => {
const configInterceptor = (config.interceptor || {})[key] || [];
const baseInterceptor = (base.interceptor || {})[key] || [];
const baseKeyInterceptor = muxLib.isArray(baseInterceptor) ? baseInterceptor : [baseInterceptor];
p[key] = compose(...baseKeyInterceptor, ...configInterceptor);
return p;
}, {});
return {
prefix,
fetchOption,
responseHandle,
interceptor
};
};
/**
* 默认配置
*/
const DEFAULT_CONFIG = {
prefix: "",
fetchOption: {},
responseHandle: async res => {
const data = await res.response.clone().json();
return { ...data,
...res.options
};
},
interceptor: {
requestInterceptor: compose(),
responseInterceptor: compose(),
errorInterceptor: compose()
}
};
/**
* 请求类型
*/
const JSON_TYPE = "application/json";
const FORM_DATA_TYPE = "multipart/form-data;";
/**
* 匹配http,https
*/
const URL_HTTP_REG = /^http(s?)\:\/\//;
const globalConfigMap = new Map([["config", DEFAULT_CONFIG]]);
const setGlobalConfig = (config = {}) => {
/**
* 开始前,进行必要的检查
*/
checkGlobalConfig(config);
/**
* 对参数进行处理
*/
const params = configFactory(config);
globalConfigMap.set("config", params);
};
const blockConfigMap = new Map();
const setBlockConfig = (namespace, config = {}) => {
/**
* 开始前,进行必要的检查
*/
checkGlobalConfig(config);
/**
* 对参数进行处理
*/
const params = configFactory(config);
blockConfigMap.set("namespace", namespace);
blockConfigMap.set(namespace, params);
};
/**
* 默认加上请求方法,第二个参数约定为请求参数
*/
const fastFetchFactory = (fetch, opts) => (api, params = {}, ...args) => fetch(api, {
body: params || {},
...opts
}, ...args);
/**
* 默认的配置项
*/
const createDefaultConfig = () => globalConfigMap.get("config");
const fetchWebapi = async (api, opts = {}, getConfig = createDefaultConfig) => {
/**
* getConfig 必须在运行时调用,才能保证获取的配置是最新的
* @returns interceptor
* @returns prefix
* @returns fetchOption
*/
const {
interceptor,
prefix,
fetchOption,
responseHandle
} = getConfig();
const {
requestInterceptor,
responseInterceptor,
errorInterceptor
} = interceptor;
let url, options, startTime, endTime;
try {
/**
* 请求拦截器
*/
const request = requestInterceptor({
api: URL_HTTP_REG.test(api) ? api : `${prefix}${api}`,
options: Object.assign({}, fetchOption, opts)
});
url = request.api;
options = request.options;
/**
* 如果没有,默认使用fetch
* 要求必须是返回promise的方法
*/
const fetch = options.fetch || defaultFetch;
/**
* 打印请求开始时间
*/
startTime = Date.now();
const response = await fetch(url, options);
/**
* 打印请求结束时间
*/
endTime = Date.now();
/**
* 返回响应拦截器的值
*
* @example
* const responseInterceptor = res =>res.clone().json()
*
*/
const res = await responseHandle({
response,
options: {
startTime,
endTime
}
});
return responseInterceptor(res);
} catch (error) {
errorInterceptor({
error,
options: {
type: "fetch",
url,
args: {
options,
startTime,
endTime
}
}
});
}
}; // 快捷方法
fetchWebapi.get = fastFetchFactory(fetchWebapi, {
method: "GET"
});
fetchWebapi.post = fastFetchFactory(fetchWebapi, {
method: "POST"
});
fetchWebapi.put = fastFetchFactory(fetchWebapi, {
method: "PUT"
});
fetchWebapi.delete = fastFetchFactory(fetchWebapi, {
method: "DELETE"
});
fetchWebapi.upload = fastFetchFactory(fetchWebapi, {
method: "POST",
headersType: FORM_DATA_TYPE
});
const fetch = (...args) => {
let namespace, api, options;
if (!args.length) {
muxLib.invariant(false, "[fetch] fetch need one argument at least");
}
/**
* 第一种,简单的调用接口
* @example
* fetch(api)
*/
if (args.length === 1) {
api = args[0];
options = {};
}
/**
* 第二种,调用接口带参数
* @example
* 1. fetch(api,options)
* 2. fetch(namespace,api)
* */
if (args.length === 2) {
if (muxLib.isString(args[1])) {
namespace = args[0];
api = args[1];
} else {
api = args[0];
options = args[1];
}
}
/**
* 第三种,调用接口加上区块的参数
* @example
* fetch(namespace,api,options)
*/
if (args.length === 3) {
namespace = args[0];
api = args[1];
options = args[2];
}
if (!namespace) {
return fetchWebapi(api, options);
} else {
const getConfig = () => blockConfigMap.get(namespace);
return fetchWebapi(api, options, getConfig);
}
}; // 快捷方法
fetch.get = fastFetchFactory(fetch, {
method: "GET"
});
fetch.post = fastFetchFactory(fetch, {
method: "POST"
});
fetch.put = fastFetchFactory(fetch, {
method: "PUT"
});
fetch.delete = fastFetchFactory(fetch, {
method: "DELETE"
});
fetch.upload = fastFetchFactory(fetch, {
method: "POST",
headersType: FORM_DATA_TYPE
});
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
exports.FORM_DATA_TYPE = FORM_DATA_TYPE;
exports.JSON_TYPE = JSON_TYPE;
exports.URL_HTTP_REG = URL_HTTP_REG;
exports.blockConfigMap = blockConfigMap;
exports.checkGlobalConfig = checkGlobalConfig;
exports.compose = compose;
exports.configFactory = configFactory;
exports.fastFetchFactory = fastFetchFactory;
exports.fetch = fetch;
exports.fetchWebapi = fetchWebapi;
exports.globalConfigMap = globalConfigMap;
exports.normalize = normalize;
exports.normalizeFormDataParams = normalizeFormDataParams;
exports.normalizeParams = normalizeParams;
exports.setBlockConfig = setBlockConfig;
exports.setGlobalConfig = setGlobalConfig;