Skip to content

Instantly share code, notes, and snippets.

@l-7-l
Created April 25, 2022 13:26
Show Gist options
  • Save l-7-l/99f03ee35788393eba2c7f55b369c4f6 to your computer and use it in GitHub Desktop.
Save l-7-l/99f03ee35788393eba2c7f55b369c4f6 to your computer and use it in GitHub Desktop.
/* eslint-disable prefer-object-spread */
import API from 'conf/API'
import ky, { BeforeErrorHook, BeforeRequestHook } from 'ky'
import { cookieRepo } from 'store/cookie'
import { message } from 'antd'
import type { KyInstance } from 'ky/distribution/types/ky'
import type { Input, Options } from 'ky/distribution/types/options'
import { DB_PROFILE_KEY } from 'conf/constants'
export interface PaginationParams {
readonly page?: number
readonly pagesize?: number
}
export interface Pagination<T> {
readonly total: number
readonly page: number
readonly pages: number
readonly list: readonly T[]
}
export interface Response<T> {
readonly status: 'success' | 'fail'
readonly code: number
readonly data: T
readonly error?: string
readonly message?: string
}
export type HttpReq = <T>(url: Input, options?: Options) => Promise<T>
const addAuthToken: BeforeRequestHook = (request) => {
const token = cookieRepo.accessToken
if (token) {
request.headers.set('Authorization', `Bearer ${token}`)
}
}
// const refreshToken: BeforeRequestHook = (req) => {}
const commonError: BeforeErrorHook = (error) => {
const { response } = error
if (response && response.body) {
// console.log('error: res', response.json())
// error.name = 'GitHubError'
// error.message = `${response.body.message} (${response.statusCode})`
}
return error
}
export class Net {
readonly #ky: KyInstance
readonly get: HttpReq
readonly post: HttpReq
readonly put: HttpReq
readonly delete: HttpReq
readonly patch: HttpReq
static #instance: Net
static get instance() {
if (!Net.#instance) {
Net.#instance = new Net()
}
return Net.#instance
}
static readonly apiClient = (prefixUrl: string = API.baseUrl) =>
ky.extend({
prefixUrl,
mode: 'cors',
credentials: 'omit',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
hooks: {
beforeRequest: [addAuthToken],
beforeError: [commonError],
},
})
constructor() {
this.#ky = Net.apiClient()
this.get = this.#actionCreator('get')
this.post = this.#actionCreator('post')
this.put = this.#actionCreator('put')
this.patch = this.#actionCreator('patch')
this.delete = this.#actionCreator('delete')
Net.#instance = this
}
readonly #actionCreator =
(method: Options['method']) =>
async <T>(url: Input, options?: Options) =>
this.req<T>(url, Object.assign({ method }, options))
async req<T>(url: Input, options?: Options) {
try {
const res = await this.#ky(url, options)
const json: Response<T> = await res.json()
if (json.status === 'success' && res.status === 200) {
return json.data
}
message.destroy()
message.error(json.message)
const { code } = json
// TODO: CODE ENUM
if (
code === 401201 || // 单点登录
code === 408002 || // 令牌错误
code === 408003 || // 令牌过期
code === 408004 || // 令牌无效
(document && !document.location.pathname.startsWith('/login'))
) {
document.location.assign('/login')
if (localStorage) localStorage.removeItem(DB_PROFILE_KEY)
}
throw Error(json.error)
} catch (err) {
message.destroy()
throw err
}
}
pagination<T, R>(
url: string,
converter: (data: Pagination<T>) => R
): (page?: number, pageSize?: number) => Promise<R>
pagination<T>(
url: string
): (page?: number, pageSize?: number) => Promise<Pagination<T>>
pagination<T, R>(url: string, converter?: (data: Pagination<T>) => R) {
return async (page = 1, pageSize = 20) => {
const data = await this.req<Pagination<T>>(url, {
searchParams: {
page,
pagesize: pageSize,
},
})
if (converter) return converter(data)
return data
}
}
}
export default Net.instance
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment