npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@segma/api-tools

v0.2.8

Published

api tools used in most projects

Downloads

9

Readme

@segma/api-tools

简介

这是一个与构建 api 请求相关的工具包,包含了定制 axios 实例、认证 token 的管理、基于 vue 的认证 mixin、构建可取消、可 mock 数据的 api 请求等功能。

仓库地址

https://github.com/RanSatious/segma-api

快速开始

安装

# 切换仓库
npm config set registry http://npm.segma.tech/
npm i @segma/api-tools

使用

import { ApiFactory, getToken, setToken, clearToken, AuthChecker, initBuilder } from '@segma/api-tools';

ApiFactory

我们通常使用 axios 来请求后端接口,但在实际使用时,往往需要对 axios 实例进行一些定制化的配置来适应后端接口的一些通用的约定,如返回数据格式、验证机制、错误处理等等。

这些通用的约定一般是作为团队的代码规范,不会随着项目而变化,所以在以往的实践中,前端需要在每个项目里去编写这样一份相同的配置,这是重复性的工作,需要进行改进。

于是,api-tools 提供了 ApiFactory 函数,可以快速生成一个已经拥有默认配置的 axios 实例。

快速使用

import { ApiFactory, SegmaStrategy } from '@segma/api-tools';

const axios = ApiFactory({
    tip: console.log,
    auth: SegmaStrategy,
    axiosConfig: {
        baseURL: process.env.VUE_APP_BASE_API,
    },
});

async function request() {
    let result = await axios.get('http://localhost:7000/api');
    console.log(result);
}

接口定义

import { AxiosInstance } from 'axios';

declare function ApiFactory(config: IApiConfig): AxiosInstance;

interface IApiResult {
    // 错误码
    code: number | string;
    // 返回提示信息
    message: string;
    // 跟踪id
    traceId?: string | null;
    // 导致错误的可能原因
    possibleReason?: string | null;
    // 建议采取的解决问题的措施
    suggestMeasure?: string | null;
    // 返回数据
    data?: unknown;
}

interface IApiConfig {
    // 提示接口错误消息的函数
    tip: (message: string, code?: number | string, result?: IApiResult) => void;
    // axios 配置
    // 会与默认的 axios 配置进行合并
    axiosConfig?: AxiosRequestConfig;
    // 认证策略
    auth?: IAuthStrategy;
}

interface IAuthStrategy {
    // 在请求前调用
    onAuth: (config: AxiosRequestConfig) => Promise<void>;
    // 在请求返回401时调用
    onUnauthorized: (error?: AxiosError) => void;
}

默认配置

import qs from 'qs';

const defaultConfig: IApiConfig = {
    tip: console.log,
    axiosConfig: {
        baseURL: '',
        headers: { 'X-Requested-With': 'XMLHttpRequest' },
        transformResponse: (data: any) => {
            if (typeof data === 'string' && data[0] === '{') {
                return JSON.parse(data);
            } else {
                return data;
            }
        },
        paramsSerializer: function (params) {
            return qs.stringify(params, { arrayFormat: 'brackets' });
        },
    },
};

SegmaStrategy

Segma 的认证策略

const SegmaStrategy: IAuthStrategy = {
    async onAuth(config) {
        config.headers['Authorization'] = await getToken();
    },
    onUnauthorized(error) {
        let redirect = process.env.VUE_APP_AUTH_REDIRECT_URI;
        let clientId = process.env.VUE_APP_AUTH_CLIENT_ID;
        if (redirect && clientId) {
            setTimeout(() => {
                logout(`${redirect}?state=xyz&client_id=${clientId}&redirect_uri=${encodeURIComponent(window.location.href)}`);
            }, 500);
        }
    },
};

QingtuiStrategy

轻推的认证策略

const QingtuiStrategy: IAuthStrategy = {
    async onAuth(config) {
        config.headers['Authorization'] = await getToken();
    },
    onUnauthorized(error) {
        let redirect = process.env.VUE_APP_AUTH_REDIRECT_URI;
        if (redirect) {
            setTimeout(() => {
                logout(`${redirect}?uri=${encodeURIComponent(window.location.href)}`);
            }, 500);
        }
    },
};

token manager

token 的管理主要与 axios 实例,AuthChecker 一起使用,做到与业务代码基本解耦,日常的开发不需要关心 token 如何处理。

快速使用

import { getToken, setToken, clearToken } from '@segma/api-tools';

// 获取 token
// 注意是异步操作
let token;
getToken().then(result => {
    token = result;
});

// 设置 token
setToken('token_value');

// 清理 token
clearToken();

接口定义

// 对应 strategy 的 get 操作
declare const getToken: () => Promise<string>;
// 对应 strategy 的 set 操作
declare const setToken: (token?: string | null) => void;
// 对应 strategy 的 remove 操作
declare const clearToken: () => void;

管理策略

一个 token 的管理策略包含了 get/set/remove 3 种操作,具体参见下面的接口定义,你可以自由添加、选择 token 的管理策略,默认提供 localstorage 的策略。

interface IStrategy {
    get: (name: string) => string | null;
    set: (name: string, value: string) => void;
    remove: (name: string) => void;
}
declare const addStrategy: (name: string, payload: IStrategy, force?: boolean) => void;
declare const selectStrategy: (name?: string) => IStrategy;
export { addStrategy, selectStrategy };

虽然提供了变更管理策略的能力,但请谨慎使用。

todo

  • 自定义 token 的名称,现在固定为 auth_token。

AuthChecker

通过 AuthChecker 快速创建一个可以获取、保存、检查 token 是否存在的 mixin。

快速使用

// 创建 mixin
// src/plugins/mixins/auth.js
import { AuthChecker } from '@segma/api-tools';

export default AuthChecker();
// 使用 mixin
// 在需要验证 token 的布局、视图甚至组件文件中,引入 mixin
// src/components/layout/Default.vue
import auth from '../../plugins/mixins/auth';

export default {
    name: 'DefaultLayout',
    mixins: [auth],
};

接口定义

interface IAuthConfig {
    // 是否在获取不到 token 时自动登出
    autoLogout: boolean;
    // logout 的具体操作
    logout: Function;
}

默认配置

import { SegmaStrategy } from '../api';

const defaultConfig: IAuthConfig = {
    autoLogout: true,
    logout: () => {
        SegmaStrategy.onUnauthorized();
    },
};

api builder

通过 ApiFactory 可以快速构建出满足前后端约定的 axios 实例,但是在实际的开发过程中,下面的一些场景仍会造成一些麻烦:

  • 请求报错,检查了很久,才发现是请求参数写错了
  • 后端接口迟迟不给出来,接口联调陷入僵局
  • 每个请求都需要重复地去控制加载状态
  • 网络波动,第一次请求的数据比第二次请求的数据还要后返回,测试提了 bug

api builder 可以轻松解决以上所有痛点:

  • (规划中)请求预处理,包括并不限于日志输出、参数格式化等
  • 开放接口的 mock 能力,轻松切换 mock 与真实请求
  • 监测接口的状态变化,减少重复代码的编写
  • 接口的可取消能力

初始化

初始化的目的主要是为了指定 axios 实例,并返回 buildApi 函数来构建请求。

快速使用

// 初始化
import { initBuilder } from '@segma/api-tools';

const buildApi = initBuilder({
    axios,
    log: console.log,
});

接口定义

import { AxiosInstance } from 'axios';

declare function initBuilder(config: BuilderConfig): (config: ApiBuilderConfig) => ApiFunction;

interface BuilderConfig {
    // axios 实例
    axios: AxiosInstance;
    // 日志函数
    log: (name: string, ...args: any[]) => void;
}

默认配置

import Axios from 'axios';

let defaultBuilderConfig: BuilderConfig = {
    axios: Axios,
    log: console.log,
};

与 ApiFactory 集成

import { ApiFactory, initBuilder } from '@segma/api-tools';

const buildApi = initBuilder({
    axios: ApiFactory({
        tip: console.log,
        auth: true,
        redirect: process.env.VUE_APP_AUTH_REDIRECT_URI,
    }),
    log: console.log,
});

构建 api

首先完成初始化操作

快速使用

import { initBuilder } from '@segma/api-tools';

const buildApi = initBuilder();

const api = buildApi({
    name: 'test',
    axios: () => ({
        url: 'http://localhost:7000/api',
        method: 'GET',
    }),
    isMock: false,
});

const request = async () => {
    let result = await api.test({ page: 1 });
    console.log(result);
};

request();

接口定义

import { AxiosRequestConfig } from 'axios';

declare function initBuilder(config: BuilderConfig): (config: ApiBuilderConfig) => ApiFunction;

interface ApiBuilderConfig {
    // 接口名称,供内置的日志功能使用
    name: string;
    // 返回 axios 请求参数的函数
    // 详情可参考:https://github.com/axios/axios#request-config
    axios: (params?: unknown) => AxiosRequestConfig;
    // 返回 mock 数据的方法
    // 接收 axios 方法返回的 AxiosRequestConfig 作为参数
    mock: (config?: AxiosRequestConfig) => Promise<any>;
    // 是否 mock 数据
    isMock: boolean;
    // 接口是否可以执行取消操作,为 true 时,返回的接口函数会多出 cancel/getToken 2个方法
    cancel?: boolean;
    // 是否监测接口的状态变化,为 true 时,返回的接口函数会多出 callback 1个方法
    callback?: boolean;
}

interface ApiFunction extends Function {
    cancel?: (message: string) => void;
    getToken?: () => Function | null;
    callback?: Function;
}

mock 请求

import { initBuilder } from '@segma/api-tools';

const buildApi = initBuilder();

const api = buildApi({
    name: 'test',
    mock: async () => 'mock result',
    isMock: true,
});

注意事项

  • mock 需要返回一个 Promise 或是一个 async 函数
  • 可搭配 mockjs 使用
  • isMock 为 true 时,mock 必须设置,axios 则不用;为 false 时,axios 必须设置,mock 则不用

取消请求

import { initBuilder } from '@segma/api-tools';

const buildApi = initBuilder();

const api = buildApi({
    name: 'test',
    axios: () => ({
        url: 'http://localhost:7000/api/wait',
        method: 'GET',
    }),
    isMock: false,
    cancel: true,
});

const request = async () => {
    api.cancel();
    let result = await api();
    console.log(result);
};

request();

方法说明

  • cancel(): void

取消当前正在进行的请求,需要注意取消只是客户端单方面的行为,不会影响到服务端。

  • getToken(): Function | null

获取内部的取消函数,可能为空,主要用于判断接口是否处于请求状态。

let loading = false;
api.callback(status => {
    loading = status === 'start' || (status === 'error' && api.getToken());
});

注意事项

  • 不管是 mock 还是真实请求,都支持取消
  • 不能在会导致数据变更的接口(大部分 POST 请求,PUT、DELETE 请求)上执行取消操作

监测接口状态

import { initBuilder } from '@segma/api-tools';

const buildApi = initBuilder();

const api = buildApi({
    name: 'test',
    axios: () => ({
        url: 'http://localhost:7000/api/wait',
        method: 'GET',
    }),
    isMock: false,
    cancel: true,
    // 监测接口状态的开关
    callback: true,
});

let loading = false;
api.callback(status => {
    loading = status === 'start' || (status === 'error' && api.getToken());
});

const request = async () => {
    api.cancel();
    let result = await api();
    console.log(result);
};

// 对比以前的写法,不用再去使用 try/catch/finally 来控制加载状态,代码变得简洁
// 当然在串联多个异步操作时,仍可以使用以前的写法
const oldRequest = async () => {
    try {
        loading = true;
        let result = await api();
        console.log(result);
    } catch (error) {
        // handle error
    } finally {
        loading = false;
    }
};

request();

方法说明

  • callback((status: 'start' | 'success' | 'error', ...args: any[]) => void): void

接收一个回调函数作为参数,回调函数的第一个参数 status 表示了接口当前的状态,只会是 start/success/error 这 3 个其中之一;后续参数会根据 status 的值而变化:

  • start:无后续参数
  • success:后续参数为接口返回的结果
  • error:后续参数为接口返回的错误

todo

  • 整合 ApiFactory 与 api builder