@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
pnpm add @bubblesjs/request alova
npm install @bubblesjs/request alova
yarn add @bubblesjs/request alova
bun add @bubblesjs/request alova
Quick Start
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:
{
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.
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
Matching Rules
statusMap.success and statusMap.unAuthorized accept a number, an array of
numbers, or a function:
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:
const request = createInstance({
responseCodeKey: 'status',
responseMessageKey: 'msg',
codeMap: {
success: [0, 'OK'],
unAuthorized: [401, 'TOKEN_EXPIRED']
}
})
The following options can be overridden on a single request through meta:
isWrapped
isTransformResponse
isShowSuccessMessage
isShowErrorMessage
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:
// 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.
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
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
}