@sttot/axios-api
TypeScript icon, indicating that this package has built-in type declarations

0.2.5 • Public • Published

Api - 基于 Axios 的标准化请求定义

为什么使用 api:

  • 逻辑分离:定义 API 和使用 API 可以分开,使用者无需自行调用 axios 并考虑相关的请求、错误拦截等逻辑;
  • 规范化:简洁地定义和使用 API,并提供一整套 TypeScript 类型推断;
  • 可拓展性:可自行设置 axios、请求预处理等操作;

安装

需要配合 axios 一起使用:

pnpm install @sttot/axios-api axios

如果你使用 React,建议使用 @sttot/axios-api-hooks,提供了更多有用的工具。

import axios from 'axios';
import { apiBase } from '@sttot/axios-api';

// 创建一个 api 工厂,使用我们引入的 axios
const api = apiBase(axios);

在 Cocos 中使用

请参考 暂时想了一个解决 npm 包引入问题的临时方案 中对 Axios 的引入方法。


使用

首先我们看看如何只使用 axios 进行请求:

import axios from 'axios';

// 定义数据类型
interface IInfo {
  id: number;
  data: string;
}

const getInfo = async (id: number): IInfo | undefined => {
  try {
    // 正式请求之前做的事情
    console.log(`Trying to get info: ${id}`);
    if (id < 0) {
      throw new Error('id should bigger or equal than 0');
    }
    // 正式请求
    const response = await axios({
      method: 'GET',
      baseUrl: 'https://api.sttot.com/info/',
      url: `${id}`,
    });
    // 处理响应之前做的事情
    console.log(`Got info: ${id}`);
    // 处理响应 + 校验
    const { data } = response;
    if (data === undefined || data.id !== id || typeof data.data !== 'string') {
      throw new Error('Invalid info data');
    }
    // 得到数据
    return data as IInfo;
  } catch (error) {
    // 处理错误 + 数据回滚
    console.error(`Fail to get info ${id}`, error);
    return undefined;
  }
};

如上请求包含了对请求参数的校验和解析,并在出错时提供回滚数据,我们可以将整个请求分为如下几部分:

  1. 在正式请求之前做一些事情,比如 console.log 打印一些信息、校验参数等;
  2. 使用传入的参数 (id) 生成 RequestConfig,即 { method: ... } 这一部分,用 RequestConfig 进行请求;
  3. 得到响应后,在处理响应之前做一些事情,比如打印日志;
  4. 对响应数据进行处理和校验;
  5. 处理以上过程中产生的错误,如果需要,则提供回滚数据;

生产环境中,如上的每个步骤都应当有,但是无论是使用 Api 的人还是定义 Api 的人都不愿意写如此长的带吗,于是会「偷工减料」,或者自己造轮子。因此使用一个相对简洁和规范的 Api 定义工具是必要的。

使用该框架可以将如上代码改写为:

// 定义一个 GET 请求
interface IInfo {
  id: number;
  data: string;
}
// 模板的第一个参数是 props 的类型,第二个参数是 result 的类型
// 还可以指定 Error 的类型等,更多请查看代码注释
const getInfoApi = api<number, IInfo | undefined>(
  // 生成 RequestConfig,进行请求
  id => ({
    method: 'GET',
    baseUrl: 'https://api.sttot.com/info/',
    url: `${id}`,
  }),
  // 处理响应 + 校验
  ({ data }) => {
    if (data === undefined || data.id !== id || typeof data.data !== 'string') {
      throw new Error('Invalid info data');
    }
    return data;
  },
  // 处理错误 + 数据回滚
  ({ error }) => {
    console.error(`Fail to get info ${id}`, error);
    return undefined;
  },
)
  // 正式请求之前做的事情
  .setBeforeRequest((_, { id }) => {
    console.log(`Trying to get info: ${id}`);
    if (id < 0) {
      throw new Error('id should bigger or equal than 0');
    }
  })
  // 处理响应之前做的事情
  .setAfterResponse((_, { id }) => console.log(`Got info: ${id}`));

虽然没有让代码变得更短,但实际上定义 Api 时需要操心的事情变少了,而且除了 api 的第一个参数(用于生成 RequestConfig)和第二个参数(用于处理结果),其余的部分都是可选的,实际上需要做什么处理可以由开发者自行决定。

在定义之后,可以很简单的使用之:

const info = await getInfoApi(1);

如果需要终止请求,可以使用 AbortController 作为第二个参数:

const controller = new AbortController();
// 1s 后取消请求
setTimeout(() => controller.abort(), 1000);
const info = await getInfoApi(1, controller);

这里重新对 Api 的设计思路进行解释:

  • 一个 Api 本身是一个黑盒,接受参数(props),进行请求(call),并返回结果(result),也可能会抛出异常,整个过程是异步的;
  • 因此,一个最简单的 Api 应该包含三个流程:处理调用的参数(CallHandler) => 进行 Axios 请求(AxiosCall) => 对请求的响应进行处理以得到数据(ResultHandler)。
  • 某些情况下,需要在进行 Axios 请求前进行额外的工作(Action Before Request),例如申请 AccessToken;
  • 在某些情况下,需要在 Axios 请求结束、得到响应后进行额外的工作(Action After Response),例如更新进度条;
  • 如上的五个过程都有可能抛出异常,因此可以对其进行处理并做一些相关的工作(ErrorHandler),进一步的,可能会重新抛出原有的/新的异常,或者返回一个默认数据;

因此整个过程可以设定五个处理函数:

  • CallHandler: 必须有,将请求参数转化为 RequestConfig,可以抛出异常,异步或者同步;
  • ResultHandler: 必须有,将响应转化为最后返回的数据,可以抛出异常,异步或者同步;
  • ErrorHandler: 可选,如果没有,Api 会抛出所有的异常;如果有,将会由该函数处理,可以自行决定是继续抛出异常,还是返回一个默认数据,异步或者同步;
  • Action(Before Request): 可选,在 CallHandler 执行之后、进行 Axios 请求之前做一些事情,可以抛出异常,异步或者同步;
  • Action(After Response): 可选,在 Axios 响应之后、ResultHandler 之前之前做一些事情,可以抛出异常,异步或者同步;

一个 Api 的定义采用参数初始化 CallHandler、ResultHandler和ErrorHandler + 链式调用进行各种设置的方式,所有链式调用函数列如下:

  • setAxiosInstance 设置 Axios 实例;
  • setDefaultAxiosConfig 设置默认的请求,会与 CallHandler 的结果合并;
  • setUrl 设置默认的 URL;
  • setMethod 设置默认的请求方法;
  • handleCall 重新设定 CallHandler;
  • handleResult 重新设定 ResultHandler;
  • handleError 重新设定 ErrorHandler;
  • setBeforeRequest 设定 Action(Before Request);
  • setAfterResponse 设定 Action(After Response);

具体用法参考 API 注释。


其他问题

如何在 ResultHandler 中拿到 RequestConfig

response.config 就是。

更多使用方法可以参考 Axios 官方文档

如何在请求失败时重试请求

在 ErrorHandler 接受参数中,有 retry 函数,调用即会重新进行请求,重试的条件请自行判断。

Readme

Keywords

none

Package Sidebar

Install

npm i @sttot/axios-api

Weekly Downloads

0

Version

0.2.5

License

none

Unpacked Size

53 kB

Total Files

19

Last publish

Collaborators

  • sttot