import 'reflect-metadata'
import { HttpRequest } from './request'
import { AxiosRequestConfig } from 'axios'
const enum CodeStatus {
SUCCESS = '000000'
}
interface HttpDecoratorOptions {
method: 'get' | 'post' | 'put' | 'delete'
url: string
config?: AxiosRequestConfig
}
const enum ParamType {
PARAMS = 'params',
RESULT = 'result',
PATH = 'path',
PATH_PRAMS = 'pathParams'
}
const enum Method {
GET = 'get',
POST = 'post',
PUT = 'put',
DLETE = 'delete'
}
const createHttpDecorator = (options: HttpDecoratorOptions) => {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const { method, url, config = {} } = options
const originalMethod = descriptor.value
descriptor.value = async function (...args: any[]) {
const paramsIndex = Reflect.getMetadata(ParamType.PARAMS, target, propertyKey)
const resultIndex = Reflect.getMetadata(ParamType.RESULT, target, propertyKey)
const pathParams = method === Method.GET ? Reflect.getMetadata(ParamType.PATH_PRAMS, target, propertyKey) || [] : []
try {
let finalUrl = url
if (method === Method.GET) {
pathParams?.forEach(({ key }) => {
finalUrl = finalUrl.replace(`{${key}}`, args?.[0][key])
})
}
const response = await HttpRequest[method](finalUrl, args[paramsIndex], config)
if (response.code == CodeStatus.SUCCESS) {
args[resultIndex] = response.data
}
return originalMethod.call(this, ...args)
} catch (error) {
throw new Error(error.message)
}
}
}
}
export const Get = (params: any) => createHttpDecorator({ ...params, method: Method.GET })
export const Post = (params: any) => createHttpDecorator({ ...params, method: Method.POST })
export const Put = (params: any) => createHttpDecorator({ ...params, method: Method.PUT })
export const Delete = (params: any) => createHttpDecorator({ ...params, method: Method.DLETE })
class ParamsDecoratorClass {
map: Map<any, any>
options: any = null
constructor(options?: any) {
this.options = options
this.map = (() => {
const map = new Map([])
map.set(ParamType.PARAMS, () => this.PARAMS(this.options))
map.set(ParamType.RESULT, () => this.RESULT(this.options))
map.set(ParamType.PATH, () => this.PATH(this.options))
return map
})()
}
private TYPE(options: any, type: ParamType) {
const { target, propertyKey, paramIndex, pathKeys = [] } = options
if (type == ParamType.PATH_PRAMS) {
const pathParams = Reflect.getMetadata(ParamType.PATH_PRAMS, target, propertyKey) || []
pathKeys?.forEach((item, sort) => {
pathParams.push({ key: item, index: sort })
})
return Reflect.defineMetadata(type, pathParams, target, propertyKey)
}
return Reflect.defineMetadata(type, paramIndex, target, propertyKey)
}
private PARAMS(options: any) {
this.TYPE(options, ParamType.PARAMS)
}
private RESULT(options: any) {
this.TYPE(options, ParamType.RESULT)
}
private PATH(options: any) {
this.TYPE(options, ParamType.PATH_PRAMS)
}
public getType(type: ParamType) {
const func = this.map.get(type)
return func?.()
}
}
const createParamsDecorator = (param: { type: ParamType; pathKeys?: Array<any> }) => {
return function (target: Object, propertyKey: string, paramIndex: number) {
const { type, pathKeys } = param
if (type != ParamType.PATH) {
return new ParamsDecoratorClass({ target, propertyKey, paramIndex }).getType(type)
}
return new ParamsDecoratorClass({ target, propertyKey, pathKeys }).getType(type)
}
}
export const Params = () => createParamsDecorator({ type: ParamType.PARAMS })
export const Result = () => createParamsDecorator({ type: ParamType.RESULT })
export const PathParam = (key?: any) => createParamsDecorator({ pathKeys: key, type: ParamType.PATH })