English
@bubblesjs/request
@bubblesjs/request is a small Alova-based request wrapper. It centralizes common headers, response transformation, business-code checks, message hooks, cache adapters, and per-request behavior switches.
Installation
bash
pnpm add @bubblesjs/request alovabash
npm install @bubblesjs/request alovabash
yarn add @bubblesjs/request alovabash
bun add @bubblesjs/request alovaQuick Start
ts
import { createInstance } from '@bubblesjs/request'
const request = createInstance({
baseUrl: '/api',
commonHeaders: {
'Content-Type': 'application/json',
Authorization: async () => `Bearer ${await getToken()}`,
},
successMessageFunc: (message) => toast.success(message),
errorMessageFunc: (message) => toast.error(message),
unAuthorizedResponseFunc: () => router.push('/login'),
})
const user = await request.Get('/user/info')
const result = await request.Post('/user/update', {
body: { name: 'John' },
})By default, a successful wrapped response is expected to look like this:
ts
{
code: 200,
data: { id: 1 },
message: 'ok'
}The returned value is the field configured by responseDataKey, so the example above resolves to { id: 1 }.
Dual Call Instance
createDualCallInstance returns a default Alova instance that can also be called as a function to create a temporary instance with merged options.
ts
import { createDualCallInstance } from '@bubblesjs/request'
const request = createDualCallInstance({
baseUrl: '/api',
isShowSuccessMessage: false,
errorMessageFunc: (message) => toast.error(message),
})
await request.Get('/user/profile')
await request({
isShowSuccessMessage: true,
successMessageFunc: (message) => toast.success(message),
}).Post('/user/create', {
body: { name: 'Jane' },
})Configuration
| Option | Type | Default | Description |
|---|---|---|---|
baseUrl | string | '/' | Base URL passed to Alova as baseURL. |
timeout | number | undefined | Request timeout. |
commonHeaders | Record<string, HeaderValue> | {} | Common headers. Values can be static or async functions. |
statusMap | StatusMap | { success: 200, unAuthorized: 401 } | HTTP status matchers. |
codeMap | CodeMap | { success: [200], unAuthorized: [401] } | Business-code matchers. |
responseCodeKey | string | 'code' | Business-code field in wrapped responses. |
responseDataKey | string | 'data' | Data field in wrapped responses. |
responseMessageKey | string | 'message' | Message field in wrapped responses. |
isWrapped | boolean | true | Whether the response uses { code, data, message } style wrapping. |
isTransformResponse | boolean | true | Whether to transform responses in responded.onSuccess. |
isShowSuccessMessage | boolean | false | Whether to call successMessageFunc after business success. |
successDefaultMessage | string | '操作成功' | Fallback success message. |
isShowErrorMessage | boolean | true | Whether to call errorMessageFunc on HTTP, business, or network errors. |
errorDefaultMessage | string | '服务异常' | Fallback error message. |
successMessageFunc | (message: string) => void | undefined | Success message hook. |
errorMessageFunc | (message: string) => void | undefined | Error message hook. |
unAuthorizedResponseFunc | () => void | undefined | Called for unauthorized HTTP status or business code. |
statesHook | StatesHook | undefined | Alova state hook for React, Vue, and other integrations. |
requestAdapter | AlovaRequestAdapter | adapterFetch() | Alova request adapter. |
cacheFor | GlobalCacheConfig | null | null | Alova global cache config. |
cacheLogger | boolean | true | Alova cache logging switch. |
l1Cache | AlovaGlobalCacheAdapter | undefined | Alova L1 cache adapter. |
l2Cache | AlovaGlobalCacheAdapter | undefined | Alova L2 cache adapter. |
storageAdapter | AlovaGlobalCacheAdapter | undefined | Backward-compatible alias for l2Cache. |
Matching Rules
statusMap.success and statusMap.unAuthorized accept a number, an array of numbers, or a function:
ts
const request = createInstance({
statusMap: {
success: [200, 201, 204],
unAuthorized: (status) => status === 401 || status === 419,
},
})codeMap.success and codeMap.unAuthorized accept arrays of numbers or strings:
ts
const request = createInstance({
responseCodeKey: 'status',
responseMessageKey: 'msg',
codeMap: {
success: [0, 'OK'],
unAuthorized: [401, 'TOKEN_EXPIRED'],
},
})Per-Request Meta
The following options can be overridden on a single request through meta:
isWrappedisTransformResponseisShowSuccessMessageisShowErrorMessage
ts
const rawResponse = await request.Get('/download/file', {
meta: {
isTransformResponse: false,
isShowErrorMessage: false,
},
})
const rawUploadData = await request.Post('/upload', {
body: formData,
meta: {
isWrapped: false,
},
})Response Shapes
The default fetch adapter returns a Response, which is parsed according to the content-type header. JSON responses are read with json(), text responses are read with text(), and JSON strings are parsed when possible.
Axios-style and Taro-style responses are also supported:
ts
// Axios-style
{
status: 200,
data: { code: 200, data: [], message: 'loaded' }
}
// Taro-style
{
statusCode: 200,
data: { code: 200, data: { ok: true }, msg: 'done' }
}For Taro upload APIs that return data as a JSON string, the string is parsed before codeMap and responseDataKey are applied.
Custom Adapter
Any Alova request adapter can be passed through requestAdapter. If the adapter also exposes a cache adapter, pass it as l2Cache or storageAdapter.
ts
import { createInstance } from '@bubblesjs/request'
import { adapterTaro } from '@alova/adapter-taro'
const taroAdapter = adapterTaro()
const request = createInstance({
baseUrl: '/api',
requestAdapter: taroAdapter.requestAdapter,
storageAdapter: taroAdapter.storageAdapter,
responseMessageKey: 'msg',
})Types
ts
type MaybePromise<T> = T | Promise<T>
type HeaderValue =
| string
| number
| boolean
| null
| undefined
| (() => MaybePromise<string | number | boolean | null | undefined>)
type StatusMatcher<RE> = number | number[] | ((status: number, response: RE) => boolean)
type CodeMatcher = Array<number | string>
interface StatusMap<RE = unknown> {
success?: StatusMatcher<RE>
unAuthorized?: StatusMatcher<RE>
}
interface CodeMap {
success?: CodeMatcher
unAuthorized?: CodeMatcher
}
interface RequestMeta {
isWrapped?: boolean
isTransformResponse?: boolean
isShowSuccessMessage?: boolean
isShowErrorMessage?: boolean
}