/petal-service

基于decorator的服务框架。支持多实例,字段装饰器,方法装饰器,class装饰器等等,开箱即用。

Primary LanguageTypeScript

环境要求

  • 支持 Map, Proxy, Reflect
  • 支持装饰器新语法, 详情参见:proposal-decorators
  • 如果使用TypeScript, TypeScript 5.0以上并且不设置experimentalDecorators。5.0的修饰器标准跟之前的修饰器是不兼容的。旧版的 --experimentalDecorators 选项将会仍然保留,如果启用此配置,则仍然会将装饰器视为旧版,新版的装饰器无需任何配置就能够默认启用。
  • 支持装饰器新语法: accessor

简单就是 E6+ + typescript 5.0 +

// 语法示例
type Decorator = (value: Input, context: {
  kind: string;
  name: string | symbol;
  access: {
    get?(): unknown;
    set?(value: unknown): void;
  };
  private?: boolean;
  static?: boolean;
  addInitializer?(initializer: () => void): void;
}) => Output | void;

说明

轻量级的装饰器服务框架,快速搭建请求服务。 比如:

import "petal-service";

// 允许打印日志
petalEnableLog(true);

// 更新配置,比如授权信息,例如jwt, cookies
petalSetConfig({
    headers: {
        token: "token",
    },
});

// 设置baseUrl和超时时间
@petalClassDecorator({
    timeout: 60 * 1000,
    baseURL: "http://www.example.com",
})
class DemoService<R> extends BaseService<R>{
    // 设置 api method 请求参数,最主要的是url, params, data和额外的config
    @methodDecorator({
        method: "get",
        url: "",
    })
    static async getIndex(
        this: DemoService<string>,
        _params: RequestParamsPick.Params<{ since: string }>
    ): Promise<string> {
        // 不写任何返回, 默认会返回 this.res.data
        return this.res.data
    }

    // 设置 实例的timeout ,优先级: 方法 > 大于实例 > class > 自定义默认值
    @fieldDecorator("timeout")
    static timeoutValue = 15 * 1000;
}

DemoService.getIndex(
    {
        params: { since: "monthly" },
        config: {
            headers: { userId: 1 },
        },
    }
)
    .then((res: any) => {
        console.log("res DemoService static getIndex:", res.length);
    })
    .catch((err) => {
        console.log("error DemoService static getIndex:", err);
    });

输出

innerStaticMethodDecorator class:DemoService, method:getIndex
innerFieldDecorator class:DemoService, field:timeoutValue
Function getIndex final config: {
  timeout: 5000,
  responseType: 'json',
  baseURL: 'https://www.example.com',
  method: 'get',
  url: '',
  headers: { userId: 1 }
}
res DemoService static getIndex: 1256

特性

  • 支持多实例: 默认示例 + 自定义实例
  • 支持多级配置
    实例模式: 方法配置 > 实例属性配置 > 实例config属性 > class的配置 > 自定义默认值 > 系统默认配置
    静态模式: 方法配置 > 静态属性配置 > 静态config属性 > class的配置 > 自定义默认值 > 系统默认配置
  • 支持服务继承
  • 支持自定义装饰器 (初级)
  • 支持path路径参数,即 /user/:id/user/{id} 格式
  • 支持getter
  • 支持accessor
     @accessorDecorator()
     accessor timeout: number = 15 * 1000;
  • 支持静态方法和静态属性
  • 支持基于Axios自定义request
  • 支持拦截器, 可以通过基于Axios自定义request实现
  • 支持实例属性config作为配置
  • 支持静态属性config作为配置
  • 内置BaseServiceClass,快捷使用 res和config属性
  • 全局暴露默认实例装饰器
  • 支持日志开关
enableLog(true)      // 自行引入
petalEnableLog(true) // 全局暴露
  • 支持查询方法配置
console.log("getIndex config", getMethodConfig(DemoService, DemoService.getIndex));
// 输出
getIndex config: {
  classConfig: {},
  methodConfig: { config: { url: 'https://baidu.com/' } },
  propertyConfig: {},
  fieldConfig: { timeout: 20000 },
  defaultConfig: {}
}
  • 支持统计
const ins = new DemoService();
const result = getStatistics(ins);
console.log(JSON.stringify(result, undefined , "\t"));

//输出
{
	"instanceMethods": {
		"count": 1,
		"methods": [
			{
				"name": "getIndex",
				"class": "DemoService"
			}
		]
	},
	"staticMethods": {
		"count": 1,
		"methods": [
			{
				"name": "getStaticIndex",
				"class": "DemoService"
			}
		]
	}
}
  • 支持npm安装
npm install petal-service
  • 增强自定义装饰器的介入能力? (TODO::)
  • json配置转服务 (TODO::))

使用示例

代码思路和存储

参见 design.md

注意

  1. TypeScript 5.0 的修饰器标准跟之前的修饰器是不兼容的。旧版的 --experimentalDecorators 选项将会仍然保留,如果启用此配置,则仍然会将装饰器视为旧版,新版的装饰器无需任何配置就能够默认启用。
  2. 不能装饰私有的属性,方法,getter,accessor,否则会报错
  3. 被methodDecorator装饰器装饰过的方法访问私有属性会报错,因为这里的this是一个代理对象。
    关于代理对象不能访问私有属性,参见:
    @methodDecorator({
        url: "https://baidu.com"
    })
    async getIndex(this: DemoService<string>): Promise<string> {
        console.log('this.#name', this.#name);   // 报错
        return this.res.data;
    }

    #name = 10;

TODO

  • 支持getter
  • 去除lodash
  • class属性的private检查?
    // context.private : false
    @fieldDecorator("baseURL")
    private baseURLValue = "https://www.google.com"

    // context.private : true
    @fieldDecorator("baseURL")
    #baseURLValue = "https://www.google.com"
  • 优化代理 (无需)
    • Proxy.revocable,方法执行前进行代理,执行完毕后,取消代理
    • Proxy
  • 查询方法的各个配置, 入参 class|instance, method
    • 实例方法 {defaultConfig, classConfig, methodConfig, propertyConfig, fieldConfig}
    • 静态方法 {defaultConfig, classConfig, methodConfig, propertyConfig, fieldConfig }
  • 统计
  • setRequestInstance参数修改为函数,传入内置的创建实例的函数,配置,实例等
  • dataStore存储关系图
  • 调整存储结构
  • 支持模拟参数,获取最后请求参数
  • 重复装饰问题, method和class重复装饰,会logger.warn
  • 支持cache?, 参考make-fetch-happen
  • 支持mock? 参见 axios-mock-adapter
  • 下移mergeConfig,在调用中合并config,然后再发http请求,解决访问私有变量|属性???
  • 服务请求TypeScript提示问题
  • 编写文档
  • 编写文章
  • yapi 和 swagger 转 service,参见 yapi-to-petal-serviceswagger-to-petal-service
  • node-fetch 版本?