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

@sttot/axios-api

v0.2.5

Published

为什么使用 api:

Downloads

3

Readme

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 函数,调用即会重新进行请求,重试的条件请自行判断。