UNPKG

@amanooo/fetch

Version:
164 lines (135 loc) 4.69 kB
import { commonHeaders, obj2urlParams, timeout, delay, filter200Status, cost, commonRetryOpts } from './util' import * as fetchImport from 'isomorphic-unfetch' const fetch = (fetchImport.default || fetchImport) as typeof fetchImport.default enum Color { // blue = 'color:blue', // red = 'color:red' blue = '', red = '' } type Request = RequestInit interface RetryOptions { retries?: number timeout?: number, delay?: number } export default class Fetch { static headers = commonHeaders() static credentials: RequestCredentials = "same-origin" static debug: boolean = false static retryOpts: RetryOptions = commonRetryOpts() public static async get(url: string, params: Object = {}, options: RequestInit = {}, retryOpts: RetryOptions = {}): Promise<any> { const completeUrl = url + obj2urlParams(params) const _options = { headers: { ...this.headers, 'content-type': 'text/plain' } as HeadersInit, credentials: this.credentials, ...options } const result = await this.fetch(completeUrl, _options, retryOpts) return result } public static async post(url: string, body: any = {}, options: RequestInit = {}, retryOpts: RetryOptions = {}): Promise<any> { this.debug && console.debug('__post__:', url) const _options = { method: 'POST', body: JSON.stringify(body), headers: this.headers, credentials: this.credentials, ...options } const result = await this.fetch(url, _options, retryOpts) return result } public static async put(url: string, body: Object = {}, options: RequestInit = {}, retryOpts: RetryOptions = {}): Promise<any> { const _options = { method: 'PUT', body: JSON.stringify(body), headers: this.headers, credentials: this.credentials, ...options } const result = await this.fetch(url, _options, retryOpts) return result } public static async delete(url: string, body: Object = {}, options: RequestInit = {}, retryOpts: RetryOptions = {}): Promise<any> { const _options = { method: 'DELETE', body: JSON.stringify(body), headers: this.headers, credentials: this.credentials, ...options } const result = await this.fetch(url, _options, retryOpts) return result } public static async fetch(url: string, options: RequestInit, retryOpts: RetryOptions = {}) { const start = new Date() const mark = `__${(options.method || 'GET').toLowerCase()}__` this.debug && console.debug('%s: %s, options', mark, url, options) const _retryOpts = { ...commonRetryOpts(), ...this.retryOpts, ...retryOpts } const action = (_: Function) => { return fetch(url, options) .then(filter200Status) .catch((e: Error) => { console.error('%s %s:%s Error Cost %f ms', Color.red, mark, url, cost(start), e) throw e }) } const result = await retry(action, _retryOpts) this.debug && console.debug('%s %s: %s Success Cost %f ms res: %o', Color.blue, mark, url, cost(start), result) return result } } function bail(err: Error) { throw (err || new Error('Aborted')) } type Action = (bail?: Function) => Promise<any> async function retry(action: Action, options) { const { retries, timeout: _timeout, delay: _dealy } = options function doAction() { return Promise.race([timeout(_timeout), action()]) } let times = 1 let response: any while (times <= retries) { try { response = await doAction() break } catch (error) { if (times >= retries) { throw new Error(error) } await delay(_dealy) } finally { times++ } } return response } interface SucessResult<T> { error: null payload: T } interface FailResult<T> { error: string payload: null } export type IResultUtil<T = any> = SucessResult<T> | FailResult<T> export class ResultUtil { static send(error: string, payload?): IResultUtil<any> { return { error, payload } } static success(payload: any): IResultUtil { return ResultUtil.send(null, payload) } static fail(error = 'DEFAULT ERROR') { return ResultUtil.send(error) } }