不到3k的组合式请求库,soon-fetch

239 阅读3分钟

请求库也要跟上时代,从 选项式组合式 改变
soon-fetch 可根据需要,自行组装的request,没有魔法式的逻辑控制

常用的请求库如axios,ofetch等的一些缺陷:

  • 各种onRequest,onResponse,onError,得仔细查看文档才能弄清这些选项执行的时机,把原本简单的逻辑弄复杂了。
  • 限定返回类型responseType,使得当一个接口返回多种类型时,做了多余的转换。如导出报表接口,正常返回文件流,但当数据量超过10万时,返回报错信息json,提醒用户限制范围缩小数据量。默认responseType设置为blob,错误信息也会被转为blob,还需要手动加条件判断转回json.

soon-fetch的处理方式

仅提供parseUrlOptions函数,将SoonOptions 转换为原生 fetchoptions
如有特殊需要,可以根据下方的函数定制你自己的解析函数来替代 parseUrlOptions:
mergeHeaders, mergeSignals, mergeUrl, isBodyJson

const request = <T>(url: string, options?: SoonOptions): Promise<T> => {
    //合并options及baseOptions,并转换
    const [_url, _options] = parseUrlOptions({
        url,
        options,
        baseURL: "/api",
        baseOptions: {
            timeout: 20 * 1000,
            headers: { Authorization: localStorage.getItem("token") ?? "" },
        },
    })

    return fetch(_url, _options).then((res) => {
        if (res.headers.get("content-type")?.includes("json")) {
            return res.json()
        }
        else {
            return res.blob()
        }
    })
}

const soon = createSoon(request);


/** GET */
soon.get("/user?id=123");
soon.get("/user", { query: { id: 123 } });
soon.get("/user/:id", { params: { id: 123 } });

/** POST */
soon.post("/login", { body: { username: "admin", password: "123456" } });

  //定义一个api
 export const getUserInfo=soon.API('/user/:id').GET()
  //使用
  getUserInfo({id:2}).then(res=>console.log(res))

  • 🌐 自动解析 rest Url 的参数
  • ⭐ 快捷定义请求 api
  • ⌛ 超时断开
  • 🔤 自动处理 JSON
  • 📏 不到 2K , zip 后会更小
  • 💡 用 typescript 有智能类型提醒

完整示例 (包含双token静默刷新,retry重试)

github: soon-admin-vue3
github: soon-admin-react-nextjs

特别功能

快捷方法
soon.get(url, options);
soon.post(url, options);
soon.put(url, options);
soon.patch(url, options);
soon.delete(url, options);
soon.head(url, options);
soon.options(url, options);
Restful Url 参数自动处理

url 包含 /:key 会解析匹配 key

soon.get("/api/user/:id", { params: { id: 1 } });
// api/user/1
soon.get("/api/:job/:year", { params: { job: "engineer", year: 5 } });
//api/engineer/5
超时
//** 请求级超时, 会覆盖实例级超时  */
soon.get(url, { timeout: 1000 * 20 });
快速定义 API
  //可以是 GET POST PATCH PUT DELETE
  //GET 请求数据传递至query,其他方法请求数据传递至body
  soon.API(url:string).POST<RequestType,ResponseType>()

  //定义一个api
 export const getUserInfo=soon.API('/user/:id').GET()
  //使用
  getUserInfo({id:2})
    .then(res=>console.log(res))
    .catch(err=>console.log(err))

  //用typescript,
 export const login=soon.API('/user/login')
    .POST<{username:string,password:string},{token:string}>()
 //开发工具会有请求和响应的智能提醒
  login({username:'admin',password:'123'}).then(res=>{
    localStorage.setItem('token', res.token);
  })

API 参考

parseUrlOptions源码如下
function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
  url: string;
  options?: Options;
  baseURL?: string;
  baseOptions?: Options;
}) {
  const { url, options, baseURL, baseOptions } = urlOptions;
  // 覆盖 baseOptions
  const _options = { ...baseOptions, ...options };

  // 以 AbortSignal.any 的方式合并 baseOptions.signal 、 options.signal 、
  // 以及 AbortSignal.timeout( _options.timeout)
  _options.signal = mergeSignals(
    [baseOptions?.signal, options?.signal],
    _options.timeout
  );

  //根据 baseURL , options.query , options.params 解析出完整的url
  const _url = mergeUrl(url, { ..._options, baseURL });

  // 自动stringify json-object类的body
  let _body = options?.body;
  let is_body_json = isBodyJson(_body);
  _options.body = is_body_json ? JSON.stringify(_body) : _body;

  //合并headers, 相同key值的header会被options.headers覆盖
  //当body 为 json ,自动添加 header "Content-Type": "application/json" }
  const headers = mergeHeaders(
    baseOptions?.headers,
    options?.headers,
    is_body_json ? { "Content-Type": "application/json" } : undefined
  );
  _options.headers = headers;

  return [_url, _options as Options & { headers: Headers }] as const;
}

如有特殊需要,可以根据下方的函数定制你自己的解析函数来替代 parseUrlOptions:
mergeHeaders, mergeSignals, mergeUrl, isBodyJson

SoonOptions
// function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
// RequestInit  为原生 fetch 的 init 选项
type SoonOptions = Omit<RequestInit, "body"> & {
    query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
    params?: Record<string, string | number>;
    timeout?: number;
    body?: RequestInit["body"] | object;
};

支持一下

喜欢 soon-fetch 的话 , 在 github 上给个 star 吧.

github: soon-fetch

安装 Installation
    npm install soon-fetch