1.0.12 • Published 2 months ago

http-api-model v1.0.12

Weekly downloads
-
License
-
Repository
-
Last release
2 months ago

安装

npm install http-api-model

简要说明

对于axios的Model化封装,参考php laravel orm,希望在前端也能有类似后端的模型概念。
使用localForage 提供模型本地缓存功能。针对每次请求的参数来存储缓存数据。
使用时包后,继承 Model 开始使用。
更新
缓存配置 single 为true 时,空参数将尝试获取缓存数据。

简要示例,包含基础模型,登录模型,数据模型。通常一个class 一个文件

import {Model} from "http-api-model";
import type {AxiosResponse} from "axios";

// 假定下面是 MyBaseModel.ts 文件

// 项目基础模型
export default class MyBaseModel extends Model {
    constructor() {
        super();
        this.config({
            baseUrl: '/apiRoot',
            method: 'post'
        });
        this.cache.config({
            use: true,
            // 使用分账号缓存
            account: () => MyBaseModel.cacheAccount,
            // account:()=>MyBaseModel.loginModel?.data.account,
        })
    }

    // 静态 token 和 cacheAccount 为自行扩展实例,模型本身没有这部分。
    protected static token = '';
    // 缓存账号值,通过登录接口设置
    protected static cacheAccount = ''
    // 可以考虑挂载 登录接口。注意只放类型,避免 import 错误。
    // protected static loginModel?:Login

    // 请求前处理config ,可添加登录信息
    protected handleRequest() {
        this._config.headers = this._config.headers || {};
        this._config.headers['token'] = MyBaseModel.token
    }

    // 自行根据接口格式,判断请求时成功还是失败
    protected handleIsSuccess(r: AxiosResponse): boolean {
        return r.status === 200;
    }

    // 自行根据请求格式,获取模型数据
    protected handleResponseData(r: AxiosResponse): this['data'] {
        // 获取接口中的数据
        return r.data.returnContent;
    }

    // handleIsSuccess  false 时
    protected handleFail(r: AxiosResponse) {
        //     请求失败了,如何处理,如展示异常提示
    }

    protected handleError(e: any) {
        //请求异常处理
    }

    protected handleEnd() {
        // 相当于 Promise.finally
        // 接口结束时调用,无论失败还是异常,都会执行。
    }
}

// 假定下面是  Login.ts 文件
export default class Login extends MyBaseModel {
    constructor() {
        super();
        this.config({
            url: 'xxx/xx'
        })
    }

    // 请求参数
    query = {
        account: '',
        password: ''
    }
    // 模型数据
    data = {
        token: '',
        account: '',
        name: '',
        age: undefined as number | undefined,
        heigiht: 0,
    }

    protected handleResponseData(r: AxiosResponse): this['data'] {
        // 获取接口中的数据
        const mData = r.data.returnContent as this['data'];
        // 设置项目身份凭证
        MyBaseModel.token = mData.token;
        MyBaseModel.cacheAccount = mData.account;
        return mData;
    }
}

const login = new Login();
login.fetch()


// 假定下方是 MyUser.ts 文件

export default class MyUser extends MyBaseModel {
    constructor() {
        super();
        this.config({
            // 这个接口用get
            method: 'get',
            url: 'xxx/xx'
        })
    }

    // 请求参数
    query = {
        id: ''
    }
    // 模型数据
    data = {
        name: '',
        age: undefined as number | undefined,
        heigiht: 0,
    }

    save() {
        return new MyUserSave().setQuery(this.data).fetch()
    }
}
// 用户保存接口 和 用户详情强相关,且仅用与保存。
// 这样的接口,可以放到 MyUser 模型文件中
class MyUserSave extends MyBaseModel {
    constructor() {
        super();
        this.config({
            // 这个接口用get
            method: 'post',
            url: 'xxx/xx'
        })
    }

    // 请求参数
    query: MyUser['data'] = {
        // 这里不重复写了
    }
}


// 这里假定已登录

const user = new MyUser();
// 设置查询参数
// user.query.id = 'id1';
user.setQuery({id: 'id1'})
// 发起请求或获取缓存
user.fetch().then(v => {
    // 使用数据
    // console.log(v.data.name);
    console.log(user.data.name);
})

Model 详细内容说明

import type { AxiosRequestConfig, AxiosResponse } from "axios";
import ModelCache from "./ModelCache";
export default class Model {
    /**
     * 模型初始化。将在调用设置config时执行,若不需要设置config,请手动执行它
     * @protected
     */
    protected initModel(): void;
    /**
     * 初始的请求参数
     * @private
     */
    private initQuery;
    /**
     * 上次请求参数
     * @private
     */
    private lastQuery;
    /**
     * 初始数据
     * @private
     */
    private init;
    /**
     * 上次请求数据
     * @private
     */
    private _last;
    /**
     * 上次请求结果数据
     */
    get last(): this['data'];
    private _isSuccess;
    protected _config: AxiosRequestConfig;
    /**
     * 设置请求配置并初始化模型,应只在construct调用
     * 也应在每个 模型 construct 中调用一次  this.config({});以完成初始化
     * @param options
     */
    config(options: AxiosRequestConfig): this;
    /**
     * 获取请求配置,不太常用
     */
    config(): AxiosRequestConfig;
    /**
     * 定义请求参数
     */
    query: any;
    /**
     * 批量设置请求参数
     * @param q
     */
    setQuery(q: Partial<this['query']>): this;
    /**
     * 将参数重置回上次请求时
     */
    resetQuery(): void;
    /**
     * 重置回最初参数
     * 请在 construct 中 initModel 或 设置 config
     * 否则可能不准确
     */
    clearQuery(): void;
    /**
     * 模型数据,从接口获取的数据(或从缓存),通常为数据字典。
     * 注意,data应为普通数据类型,不能含有函数,getter setter。否则可能缓存不全或异常。
     */
    data: any;
    /**
     * 批量设置模型数据
     * @param r
     */
    setData(r: Partial<this['data']>): this;
    /**
     * 将模型数据重置回上次请求的数据
     */
    reset(): void;
    /**
     * 将数据重置回初始化
     * 请在 construct 中 initModel 或 设置 config
     * 否则可能不准确
     */
    clearData(): void;
    private updateLast;
    /**
     * 请求是否成功,仅为 true 表示请求成功 false也能是还未请求
     */
    get isSuccess(): boolean;
    /**
     * 缓存控制类
     * @protected
     */
    readonly cache: ModelCache<this>;
    private _isCache;
    /**
     * 是否是缓存数据
     */
    get isCache(): boolean;
    protected _isFail: boolean;
    /**
     * 模型获取数据,从缓存或api获取数据
     */
    fetch(): Promise<this>;
    /**
     * 缓存模型数据
     * 只会经历  handleError  handleEnd
     */
    saveCache(): Promise<this>;
    /**
     * 接口发送时需要的参数,可抛出异常,终止请求
     * 返回值说明
     * default 存在时,会忽略 params data
     * default中的值,会根据请求类型 放入 get 或 post参数
     * params 会放入 AxiosRequestConfig.params
     * data 对应 AxiosRequestConfig.data
     * @protected
     */
    protected handleTransformQuery(): {
        default?: any;
        params?: any;
        data?: any;
    };
    /**
     * 在 handleTransformQuery 后执行
     * 请求配置处理,可修改config,比如设置登录token
     * 也可在此将上传数据,转为 FormData
     * @protected
     */
    protected handleRequest(): void;
    /**
     * 请求成功时执行,
     * 数据是否正确,默认 httpCode 200状态成功 AxiosResponse.status === 200;
     * 假设 接口格式 {status:1,msg:'',content}   AxiosResponse.data.status === 1;
     * @param r
     * @protected
     */
    protected handleIsSuccess(r: AxiosResponse): boolean;
    /**
     * 数据正确时执行(handleIsSuccess true 执行)
     * 根据自己的接口规则,从AxiosResponse中返回模型数据。
     * 注意返回原始值,当心返回 Proxy 等对象或含有函数,可能会导致异常。
     * 默认返回 AxiosResponse.data
     * 举例 接口格式 {code:1,returnContent:{},msg:''},应返回 AxiosResponse.data.returnContent
     * 也可自行调整接口数据格式,如 接口 {userName:'',userAage:0}-> 模型data{name:'',age:0}
     * @param r
     * @protected
     */
    protected handleResponseData(r: AxiosResponse): this['data'];
    /**
     * 数据异常时执行(handleIsSuccess false 执行)
     * 处理接口数据状态异常
     * @param r
     * @protected
     */
    protected handleFail(r: AxiosResponse): void;
    /**
     * 请求错误处理
     * @param e
     * @protected
     */
    protected handleError(e: any): void;
    /**
     *  请求结束处理 等于 Promise.finally,无论成功失败都会执行
     *  可以进行 接口异常日志发送等操作
     * @protected
     */
    protected handleEnd(): void;
    private _loading;
    /**
     * 模型是否请求中
     */
    get loading(): boolean;
    private set loading(value);
    /**
     * 模型loading变化处理,如可控制展示 全屏 loding效果,若有需要
     * @protected
     */
    protected handleLoading(): void;
    /**
     * 模型数据是否发生变更,不传参任意检查任意变更,,传入模型数据path,检查指定变更
     * path   'a.b','a[0].a'
     * @param path
     */
    hasChanged(path?: keyof this['data'] | string): boolean;
    private relationKey;
    /**
     * @param M  类本身,该关系未建立时会关键关联,已建立直接返回关联模型
     * @protected
     */
    protected relation<T extends Model>(M: new () => T): T;
    /**
     * @param M  关联模型实例,已设置会覆盖,未设置会设置关联
     * @protected
     */
    protected relation<T extends Model>(M: T): T;
}

模型缓存配置

import localforage from "localforage";
import type Model from "./Model";
import dayjs from "dayjs";
type ModelCacheConfig = ReturnType<typeof localforage['config']> & {
    /**
     * 是否使用缓存,默认false
     */
    use: boolean;
    /**
     * 设置过期时间,默认值 () => dayjs().add(10, 'minute'); 10分钟;false 不过期。
     */
    expireDate: () => Date | dayjs.Dayjs;
    /**
     * 账号名(唯一),给定此值时,将以此作为数据库名称。可以返回登录账号的id,用户名等,但应当保证唯一,
     * 当不同用户登录时,同一个接口可能返回不同的信息。如我发布的文章。传入此参数可根据账户缓存数据。
     * 优先级  account,name。
     * 注意,登录接口,或是通用接口(不需要登录的接口),应当设置为 false。
     * 常用情况为 项目模型基类 中  account:()=>accountModel.uniName; accountModel 中 account:undefined 。
     */
    account?: false | (() => string);
    /**
     * 是否仅保留一个缓存,默认值 false。启用时,设置缓存数据前会清空当前模型的其他缓存,使其只保留一份。
     * 如登录账户应当只有一条记录
     */
    single: boolean;
    /**
     * 过期数据是否使用,默认值 false。
     * 启用时,即使缓存数据已过期也会返回并使用。同时也会请求接口更新数据和缓存。
     */
    useExpireData: boolean;
    /**
     * 模型过期自动数据清理间隔,默认值 () => dayjs().add(10, 'minute');10分钟
     */
    clearExpireInterval: () => Date | dayjs.Dayjs;
    /**
     * 应当很少能用到
     * 序列化存储缓存,变更会清空数据,默认false。当下载文件时,若需要缓存文件可能需要。当返回结果非常大时,可能需要
     */
    serializer: boolean;
};
/**
 * 模型的缓存控制
 */
export default class ModelCache<M extends Model> {
    constructor(model: M);
    private readonly model;
    private _localForage;
    get localForage(): LocalForage;
    private _config;
    /**
     * 设置如何缓存
     * @param options
     */
    config(options: Partial<ModelCacheConfig>): M;
    config(): ModelCacheConfig;
    /**
     * 根据是否序列化,拼接仓库名
     * @param serializer
     * @private
     */
    private storeName;
    private key;
    /**
     * 将 Model.query 浅层拼接为key,忽略 空置,复杂数据仅使用类型名
     * boolean 转为 01
     * @param up
     * @private
     */
    private getKey;
    private convertToKeyValueString;

    protected getItem(request: () => void): Promise<any>;

    protected setItem(val: any): Promise<unknown>;
    /**
     * 移除本条缓存,列如某个列表删除一条数据后,需要移除后重新从接口获取数据
     */
    removeItem(): Promise<unknown>;
    private expireMan;
    /**
     * 清除模型所有过期数据
     */
    clearExpire(): Promise<void>;
    private isExpire;
    /**
     * 清空本模型的所有缓存
     */
    clear(): Promise<void>;
    /**
     * 删除数据仓库(数据表)
     */
    delStore(): Promise<void>;
    /**
     * 清空数据库(注意配置的 name 同 name 会全部清理),会删除掉对应的数据库,请谨慎使用
     */
    delDatabase(): Promise<void>;
}
export {};
1.0.12

2 months ago

1.0.11

4 months ago

1.0.10

5 months ago

1.0.9

5 months ago

1.0.8

8 months ago

1.0.7

8 months ago

1.0.6

8 months ago

1.0.5

8 months ago

1.0.4

9 months ago

1.0.3

9 months ago

1.0.1

9 months ago

1.0.0

9 months ago