soon-fetch
Version:
a request lib alternative to axios with timeout, request reusing, race, response cache ...
1,152 lines (836 loc) • 27.5 kB
Markdown
[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
<!-- omit in toc -->
### soon-fetch
**A lightweight http request lib , alternative to axios with timeout, request reusing, race, response cache ...**
> - 🌐 automatic parse restful api url parameters
> - ⭐ rapid define a request api
> - ⌛ timeout disconnect
> - 📦 request reusing
> - 🚀 request race
> - 📝 response cache
> - 🔤 automatic serialization of JSON
> - 📏 .min size less than **6K**, smaller after zip
> - 💡 smart type tips with Typescript
- [Example](#example)
- [Features](#features)
- [Shortcut](#shortcut)
- [Restful Url Params](#restful-url-params)
- [Timeout](#timeout)
- [Share pending request](#share-pending-request)
- [Response cache](#response-cache)
- [Request race](#request-race)
- [Rapid Define APIs](#rapid-define-apis)
- [API](#api)
### Example
> [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
```typescript
import { createSoon } from "soon-fetch";
const soon = createSoon(
(url, options) => {
const isGet = !options?.method || options?.method.toLocaleLowerCase() === "get"
return {
baseURL: '/api',
baseOptions: {
timeout: 20 * 1000,
headers: new Headers({
Authorization: "Bearer " + localStorage.getItem("token"),
}),
share: isGet ? true : false,
staleTime: isGet ? 2 * 1000 : 0,
},
}
},
({ parsed }) => {
return <T>() => {
return fetch(parsed.url, parsed.options).then((res) =>
res.json()
) as Promise<T>;
};
}
);
/** 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" } });
/**Define API */
export const login = soon
.POST("/user/login")
.Body<{ username: string; password: string }>()
.Send<{ token: string }>();
//the develop tools will have type tips for request and response
login({ username: "admin", password: "123" }).then((res) => {
localStorage.setItem("token", res.token);
});
```
### Features
##### Shortcut
```typescript
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 Params
url like /:key , will handle the key
```typescript
soon.get("/api/user/:id", { params: { id: 1 } });
// api/user/1
soon.get("/api/:job/:year", { params: { job: "engineer", year: 5 } });
//api/engineer/5
```
##### Timeout
```typescript
//** the request level timeout, will override the instance level timeout */
soon.get(url, { timeout: 1000 * 20 });
```
##### Share pending request
If a request is made again before the first completes, will reuse the first request instead of making a new request.
```ts
soon.get(url, { share: true });
```
##### Response cache
A cached response will be returned if the request is made again within the specified time.
```ts
soon.get(url, { staleTime: 1000 * 60 * 5 });
```
##### Request race
If a second request is made before the first completes, abort the first to avoid race conditions from out-of-order responses.
```tsx
import { useEffect, useRef, useState } from "react";
type User = { name: string; job: string };
const api = soon.GET("/api/users").Query<{ page: number }>().Send<User[]>();
export default function App() {
const refAbort = useRef([]);
const [list, setList] = useState<User[]>([]);
const [page, setPage] = useState(1);
useEffect(() => {
api({ page }, { aborts: refAbort.current })
.then(setList)
.catch(console.log);
}, [page]);
return (
<div>
<button onClick={() => setPage((pre) => pre + 1)}>next</button>
<div>
{list.map((item) => (
<div key={item.name}>{item.name}</div>
))}
</div>
</div>
);
}
```
##### Rapid Define APIs
```typescript
//can be GET POST PATCH PUT DELETE
soon.GET(url:string).Query<Query>().Send<Response>()
soon.POST(url:string).Body<Body>().Send<Response>()
//define an api
export const getUserInfo = soon.GET("/user/:id").Send();
//then use in any where
getUserInfo({ id: 2 }).then((res) => console.log(res));
//with typescript,
export const login = soon
.POST("/user/login")
.Body<{ username: string; password: string }>()
.Send<{ token: string }>();
//the develop tools will have type tips for request and response
login({ username: "admin", password: "123" }).then((res) => {
localStorage.setItem("token", res.token);
});
```
### API
#### SoonOptions
```ts
// function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
// RequestInit is fetch's init options
type SoonOptions = Omit<RequestInit, "body"> & {
body?: RequestInit["body"] | object;
query?:
| Record<
string,
| string
| number
| boolean
| null
| undefined
| (string | number | boolean | null | undefined)[]
>
| URLSearchParams;
params?: Record<string, string | number>;
timeout?: number;
aborts?: AbortController[] | never[];
share?: boolean;
staleTime?: number;
};
```
#### createSoon
Create a soon request instance.
**Parameters:**
- `getConfig`: A function to get request configuration, receives url and options, returns an object containing url, options, baseURL, and baseOptions
- `wrapper`: A wrapper function to handle request logic
**Returns:** An object containing request method and various shortcut methods
**Example:**
```javascript
const soon = createSoon(
(url, options) => ({ url, options,baseURL:'/api', baseOptions:{timeout: 5000} }),
({ parsed }) =>
async (url, options) => {
const response = await fetch(parsed.url, parsed.options);
return response.json();
}
);
// Usage example
const data = await soon.get("/api/users");
```
#### createShortApi
Factory function to create API shortcut methods.
Used to generate type-safe API calling methods, supporting path parameters, query parameters, and request body.
**Parameters:**
- `wrapper`: Wrapper function to handle actual request logic
**Returns:** An object containing GET, POST, PUT, DELETE, PATCH and other methods, each method supports chain calling
**Example:**
```javascript
const API = createShortApi(
async (url, method, params, query, body, options) => {
// Handle request logic
const _url = mergeUrl(url, { params, query });
const response = await fetch(_url, { ...options, method, body });
return response.json();
}
);
// Usage example
const getUser = API.GET("/api/users/:id").Send();
const userData = await getUser({ id: 1 });
```
#### createShortMethods
Factory function to create shortcut methods.
**Parameters:**
- `methods`: HTTP methods array
- `wrapper`: Wrapper function that receives method name and returns a function to process requests
**Returns:** Shortcut call object containing specified methods
**Example:**
```javascript
const methods = createShortMethods(["get", "post"], (method) => {
return (url, options) => fetch(url, { ...options, method });
});
// Usage: methods.get('/api/users')
```
#### parseUrlOptions
Parse URL options.
**Parameters:**
- `urlOptions`: Object containing url, options, baseURL and baseOptions
**Returns:** Tuple of processed url and options
**Example:**
```javascript
const [url, options] = parseUrlOptions({
url: "/api/users/:id",
options: { params: { id: "123" } },
baseURL: "https://api.example.com",
});
// Returns: ['https://api.example.com/api/users/123', options]
```
#### mergeHeaders
Merge multiple Headers objects.
**Parameters:**
- `headersList`: List of Headers objects to merge
**Returns:** Merged Headers object, later ones will overwrite earlier ones with the same name
**Example:**
```javascript
const headers1 = { "Content-Type": "application/json" };
const headers2 = { Authorization: "Bearer token" };
const mergedHeaders = mergeHeaders(headers1, headers2);
```
#### mergeSignals
Merge multiple AbortSignal signals.
**Parameters:**
- `signals`: Array of AbortSignals to merge
- `timeout`: Optional timeout time (milliseconds)
**Returns:** Merged AbortSignal, any signal termination will trigger termination
**Example:**
```javascript
const controller1 = new AbortController();
const controller2 = new AbortController();
const mergedSignal = mergeSignals(
[controller1.signal, controller2.signal],
5000
);
```
#### mergeUrl
Merge URL and its related parameters.
Handle baseURL, path parameters and query parameters to generate complete URL.
**Parameters:**
- `url`: Original URL
- `config`: Configuration object, including query parameters, path parameters and base URL
**Returns:** Processed complete URL
**Example:**
```javascript
const url = mergeUrl("/api/users/:id", {
params: { id: "123" },
query: { filter: "active" },
baseURL: "https://api.example.com",
});
// Returns: 'https://api.example.com/api/users/123?filter=active'
```
#### mergeOptions
Merge multiple option objects.
Merge request options, including special handling of headers and signals.
**Parameters:**
- `optionsList`: List of option objects to merge
**Returns:** Merged option object
**Example:**
```javascript
const defaultOptions = {
timeout: 5000,
headers: { "Content-Type": "application/json" },
};
const requestOptions = {
method: "POST",
body: JSON.stringify({ name: "John" }),
};
const mergedOptions = mergeOptions(defaultOptions, requestOptions);
```
#### isBodyJson
Determine if the request body is a JSON object.
Check if body is a plain object, not special types like FormData or Blob.
**Parameters:**
- `body`: Request body
**Returns:** Returns true if it is a JSON object, otherwise false
**Example:**
```javascript
isBodyJson({ name: "John" }); // true
isBodyJson(new FormData()); // false
isBodyJson("string"); // false
```
#### genRequestKey
Generate a unique identification key for the request.
Generate a unique key value based on the request's URL, method, headers, body, query parameters, etc., used for caching and request sharing.
**Parameters:**
- `req`: Request object containing url and options
**Returns:** Unique identification string of the request
**Example:**
```javascript
const key = genRequestKey({
url: "/api/users",
options: { method: "GET", params: { id: 1 } },
});
```
#### raceAbort
Race condition handling function.
Used to handle request race conditions, terminating previous requests.
**Parameters:**
- `abortController`: Controller of the current request
- `controllers`: Array of existing controllers
**Example:**
```javascript
const controller = new AbortController();
const controllers = [];
raceAbort(controller, controllers); // Terminate previous requests and add current controller
```
#### createCache
Create cache instance.
Provides request result caching function, supports expiration time.
**Returns:** Cache object containing get, set, remove methods
**Example:**
```javascript
const cache = createCache();
cache.set("key", { data: "value" }, Date.now() + 60000); // Cache for 1 minute
const data = cache.get("key");
cache.remove("key");
```
#### deepSort
Deep sort object keys.
Recursively sort the keys of an object to generate a stable object serialization result.
**Parameters:**
- `obj`: Object to sort
**Returns:** Object with sorted keys
**Example:**
```javascript
const obj = { b: 2, a: 1, c: { z: 3, y: 2 } };
const sorted = deepSort(obj);
// Returns: { a: 1, b: 2, c: { y: 2, z: 3 } }
```
#### createShare
Create request sharing instance.
Used to share the same request to avoid duplicate requests.
**Returns:** Sharing object containing get and set methods
**Example:**
```javascript
const share = createShare();
const promise = fetch("/api/data");
share.set("key", promise);
const sharedPromise = share.get("key"); // Get the same promise
```
#### createSilentRefresh
Create silent refresh instance.
Used to handle silent refresh functionality when token expires.
**Parameters:**
- `refresh_token_fn`: Function to refresh token
**Returns:** Function that accepts success and failure callbacks
**Example:**
```javascript
const silentRefresh = createSilentRefresh(async () => {
// Refresh token logic
await refreshToken();
});
// Usage example
silentRefresh(
() => console.log("Refresh successful"),
() => console.log("Refresh failed")
);
```
#### parseWithBase
Parse base URL configuration.
Process baseURL, headers, body and other configuration items to generate final request configuration.
**Parameters:**
- `urlOptions`: Object containing url, options, baseURL and baseOptions
**Returns:** Processed url, options, is_body_json and abortController
**Example:**
```javascript
const result = parseWithBase({
url: "/api/users",
options: { method: "GET" },
baseURL: "https://api.example.com",
});
```
#### toFormData
Convert object to FormData.
Used to convert plain objects to FormData format, supports files and regular values.
**Parameters:**
- `body`: Object to convert
**Returns:** Converted FormData object
**Example:**
```javascript
const formData = toFormData({
name: "John",
avatar: fileBlob,
age: 30,
});
```
[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
<!-- omit in toc -->
#### soon-fetch
**极轻量的请求库,不到 6K**
> - 🌐 自动解析 rest Url 的参数
> - ⭐ 快捷定义请求 api
> - ⌛ 超时断开
> - 📦 请求复用
> - 🚀 请求竞态
> - 📝 响应缓存
> - 🔤 自动处理 JSON
> - 📏 不到 **6K** , zip 后会更小
> - 💡 用 typescript 有智能类型提醒
- [示例](#示例)
- [特别功能](#特别功能)
- [快捷方法](#快捷方法)
- [Restful Url 参数自动处理](#restful-url-参数自动处理)
- [共享未完成的请求](#共享未完成的请求)
- [超时](#超时)
- [响应缓存](#响应缓存)
- [请求竞态](#请求竞态)
- [快速定义 API](#快速定义-api)
- [API](#api-1)
### 示例
> [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
```typescript
const soon = createSoon(
(url, options) => {
const isGet = !options?.method || options?.method.toLocaleLowerCase() === "get"
return {
baseURL: '/api',
baseOptions: {
timeout: 20 * 1000,
headers: new Headers({
Authorization: "Bearer " + localStorage.getItem("token"),
}),
share: isGet ? true : false,
staleTime: isGet ? 2 * 1000 : 0,
},
}
},
({ parsed }) => {
return <T>() => {
return fetch(parsed.url, parsed.options).then((res) =>
res.json()
) as Promise<T>;
};
}
);
/** 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 login = soon
.POST("/user/login")
.Body<{ username: string; password: string }>()
.Send<{ token: string }>();
//开发工具会有请求和响应的智能提醒
login({ username: "admin", password: "123" }).then((res) => {
localStorage.setItem("token", res.token);
});
```
### 特别功能
##### 快捷方法
```typescript
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
```typescript
soon.get("/api/user/:id", { params: { id: 1 } });
// api/user/1
soon.get("/api/:job/:year", { params: { job: "engineer", year: 5 } });
//api/engineer/5
```
##### 超时
```typescript
//** 请求级超时, 会覆盖实例级超时 */
soon.get(url, { timeout: 1000 * 20 });
```
##### 共享未完成的请求
如果在第一个请求完成之前再次发起相同的请求,则会复用第一个请求,而不是发起新的请求。
```ts
soon.get(url, { share: true });
```
##### 响应缓存
如果在指定时间内再次发起相同的请求,则会返回缓存的响应。
```ts
soon.get(url, { staleTime: 1000 * 60 * 5 });
```
##### 请求竞态
如果在第一个请求完成之前发起第二个请求,则会中止第一个请求,以避免因响应顺序错乱导致的问题。
```tsx
import { useEffect, useRef, useState } from "react";
type User = { name: string; job: string };
const api = soon.GET("/api/users").Query<{ page: number }>().Send<User[]>();
export default function App() {
const refAbort = useRef([]);
const [list, setList] = useState<User[]>([]);
const [page, setPage] = useState(1);
useEffect(() => {
api({ page }, { aborts: refAbort.current })
.then(setList)
.catch(console.log);
}, [page]);
return (
<div>
<button onClick={() => setPage((pre) => pre + 1)}>next</button>
<div>
{list.map((item) => (
<div key={item.name}>{item.name}</div>
))}
</div>
</div>
);
}
```
##### 快速定义 API
```ts
//可以是 GET POST PATCH PUT DELETE
//GET 请求数据传递至query,其他方法请求数据传递至body
soon.GET(url:string).Query<Query>().Send<Response>()
soon.POST(url:string).Body<Body>().Send<Response>()
//定义一个api
export const getUserInfo=soon.GET('/user/:id').Send()
//使用
getUserInfo({id:2}).then(res=>console.log(res))
//用typescript,
export const login=soon
.POST('/user/login')
.Body<{username:string,password:string}>()
.Send<{token:string}>()
//开发工具会有请求和响应的智能提醒
login({username:'admin',password:'123'}).then(res=>{
localStorage.setItem('token', res.token);
})
```
### API
#### SoonOptions
```ts
// function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
// RequestInit 为原生 fetch 的 init 选项
type SoonOptions = Omit<RequestInit, "body"> & {
body?: RequestInit["body"] | object;
query?:
| Record<
string,
| string
| number
| boolean
| null
| undefined
| (string | number | boolean | null | undefined)[]
>
| URLSearchParams;
params?: Record<string, string | number>;
timeout?: number;
aborts?: AbortController[] | never[];
share?: boolean;
staleTime?: number;
};
```
#### createSoon
创建一个 soon 请求实例。
**参数:**
- `getConfig`: 用于获取请求配置的函数,接收 url 和 options,返回包含 url、options、baseURL 和 baseOptions 的对象
- `wrapper`: 包装器函数,用于处理请求逻辑
**返回:** 包含 request 方法和各种快捷方法的对象
**示例:**
```javascript
const soon = createSoon(
(url, options) => ({ url, options,baseURL:'/api', baseOptions:{timeout: 5000} }),
({ parsed }) =>
async (url, options) => {
const response = await fetch(parsed.url, parsed.options);
return response.json();
}
);
// 使用示例
const data = await soon.get("/api/users");
```
#### createShortApi
创建 API 快捷方法的工厂函数。
用于生成类型安全的 API 调用方法,支持路径参数、查询参数和请求体。
**参数:**
- `wrapper`: 包装函数,用于处理实际的请求逻辑
**返回:** 包含 GET、POST、PUT、DELETE、PATCH 等方法的对象,每个方法都支持链式调用
**示例:**
```javascript
const API = createShortApi(
async (url, method, params, query, body, options) => {
// 处理请求逻辑
const _url = mergeUrl(url, { params, query });
const response = await fetch(_url, { ...options, method, body });
return response.json();
}
);
// 使用示例
const getUser = API.GET("/api/users/:id").Send();
const userData = await getUser({ id: 1 });
```
#### createShortMethods
创建快捷方法的工厂函数。
**参数:**
- `methods`: HTTP 方法数组
- `wrapper`: 包装函数,接收方法名,返回处理请求的函数
**返回:** 包含指定方法的快捷调用对象
**示例:**
```javascript
const methods = createShortMethods(["get", "post"], (method) => {
return (url, options) => fetch(url, { ...options, method });
});
// 使用: methods.get('/api/users')
```
#### parseUrlOptions
解析 URL 选项。
**参数:**
- `urlOptions`: 包含 url、options、baseURL 和 baseOptions 的对象
**返回:** 处理后的 url 和 options 元组
**示例:**
```javascript
const [url, options] = parseUrlOptions({
url: "/api/users/:id",
options: { params: { id: "123" } },
baseURL: "https://api.example.com",
});
// 返回: ['https://api.example.com/api/users/123', options]
```
#### mergeHeaders
合并多个 Headers 对象。
**参数:**
- `headersList`: 要合并的 Headers 对象列表
**返回:** 合并后的 Headers 对象,后面的会覆盖前面的同名 header
**示例:**
```javascript
const headers1 = { "Content-Type": "application/json" };
const headers2 = { Authorization: "Bearer token" };
const mergedHeaders = mergeHeaders(headers1, headers2);
```
#### mergeSignals
合并多个 AbortSignal 信号。
**参数:**
- `signals`: 要合并的 AbortSignal 数组
- `timeout`: 可选的超时时间(毫秒)
**返回:** 合并后的 AbortSignal,任意一个信号终止都会触发终止
**示例:**
```javascript
const controller1 = new AbortController();
const controller2 = new AbortController();
const mergedSignal = mergeSignals(
[controller1.signal, controller2.signal],
5000
);
```
#### mergeUrl
合并 URL 及其相关参数。
处理 baseURL、路径参数和查询参数,生成完整 URL。
**参数:**
- `url`: 原始 URL
- `config`: 配置对象,包含查询参数、路径参数和基础 URL
**返回:** 处理后的完整 URL
**示例:**
```javascript
const url = mergeUrl("/api/users/:id", {
params: { id: "123" },
query: { filter: "active" },
baseURL: "https://api.example.com",
});
// 返回: 'https://api.example.com/api/users/123?filter=active'
```
#### mergeOptions
合并多个选项对象。
合并请求选项,包括 headers 和 signal 等特殊处理。
**参数:**
- `optionsList`: 要合并的选项对象列表
**返回:** 合并后的选项对象
**示例:**
```javascript
const defaultOptions = {
timeout: 5000,
headers: { "Content-Type": "application/json" },
};
const requestOptions = {
method: "POST",
body: JSON.stringify({ name: "John" }),
};
const mergedOptions = mergeOptions(defaultOptions, requestOptions);
```
#### isBodyJson
判断请求体是否为 JSON 对象。
检查 body 是否为普通对象,而不是 FormData、Blob 等特殊类型。
**参数:**
- `body`: 请求体
**返回:** 如果是 JSON 对象返回 true,否则返回 false
**示例:**
```javascript
isBodyJson({ name: "John" }); // true
isBodyJson(new FormData()); // false
isBodyJson("string"); // false
```
#### genRequestKey
生成请求的唯一标识键。
根据请求的 URL、方法、headers、body、查询参数等生成唯一键值,用于缓存和请求共享。
**参数:**
- `req`: 包含 url 和 options 的请求对象
**返回:** 请求的唯一标识字符串
**示例:**
```javascript
const key = genRequestKey({
url: "/api/users",
options: { method: "GET", params: { id: 1 } },
});
```
#### raceAbort
竞态处理函数。
用于处理请求竞态,终止之前的请求。
**参数:**
- `abortController`: 当前请求的控制器
- `controllers`: 已存在的控制器数组
**示例:**
```javascript
const controller = new AbortController();
const controllers = [];
raceAbort(controller, controllers); // 终止之前的请求并添加当前控制器
```
#### createCache
创建缓存实例。
提供请求结果缓存功能,支持过期时间。
**返回:** 包含 get、set、remove 方法的缓存对象
**示例:**
```javascript
const cache = createCache();
cache.set("key", { data: "value" }, Date.now() + 60000); // 缓存1分钟
const data = cache.get("key");
cache.remove("key");
```
#### deepSort
深度排序对象键。
递归地对对象的键进行排序,用于生成稳定的对象序列化结果。
**参数:**
- `obj`: 要排序的对象
**返回:** 键排序后的对象
**示例:**
```javascript
const obj = { b: 2, a: 1, c: { z: 3, y: 2 } };
const sorted = deepSort(obj);
// 返回: { a: 1, b: 2, c: { y: 2, z: 3 } }
```
#### createShare
创建请求共享实例。
用于共享相同请求,避免重复请求。
**返回:** 包含 get 和 set 方法的共享对象
**示例:**
```javascript
const share = createShare();
const promise = fetch("/api/data");
share.set("key", promise);
const sharedPromise = share.get("key"); // 获取相同 promise
```
#### createSilentRefresh
创建静默刷新实例。
用于处理 token 过期时的静默刷新功能。
**参数:**
- `refresh_token_fn`: 刷新 token 的函数
**返回:** 接收成功和失败回调的函数
**示例:**
```javascript
const silentRefresh = createSilentRefresh(async () => {
// 刷新token逻辑
await refreshToken();
});
// 使用示例
silentRefresh(
() => console.log("刷新成功"),
() => console.log("刷新失败")
);
```
#### parseWithBase
解析基础 URL 配置。
处理 baseURL、headers、body 等配置项,生成最终的请求配置。
**参数:**
- `urlOptions`: 包含 url、options、baseURL 和 baseOptions 的对象
**返回:** 处理后的 url、options、is_body_json 和 abortController
**示例:**
```javascript
const result = parseWithBase({
url: "/api/users",
options: { method: "GET" },
baseURL: "https://api.example.com",
});
```
#### toFormData
将对象转换为 FormData。
用于将普通对象转换为 FormData 格式,支持文件和普通值。
**参数:**
- `body`: 要转换的对象
**返回:** 转换后的 FormData 对象
**示例:**
```javascript
const formData = toFormData({
name: "John",
avatar: fileBlob,
age: 30,
});
```
[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
<!-- omit in toc -->
##### 安装 Installation
```bash
npm install soon-fetch
```