A Comprehensive Guide to Building a Flexible Axios Wrapper with Interceptors, Request Cancellation, and TypeScript in Vue3
This article demonstrates how to create a reusable Axios wrapper for Vue3 projects, covering basic class‑based encapsulation, flexible global and instance interceptors, custom request configuration types, request cancellation management, and practical testing examples, all written in TypeScript.
Although the Fetch API is widely adopted, many legacy browsers still lack support and Axios continues to receive millions of weekly downloads, indicating its indispensable role. This guide walks through building a flexible, reusable Axios wrapper that provides ubiquitous code hints, adaptable interceptors, multiple instances, per‑instance configuration, and request cancellation.
Basic Wrapper
The core starts with a simple class that creates an Axios instance and exposes a request method:
// index.ts
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
class Request {
// axios instance
instance: AxiosInstance
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config)
}
request(config: AxiosRequestConfig) {
return this.instance.request(config)
}
}
export default RequestUsing a class instead of a function allows creation of multiple instances, enhancing reusability and encapsulation.
Interceptor Wrapping
Three interceptor levels are defined: class interceptors, instance interceptors, and per‑API interceptors. The class interceptor attaches global request/response handlers:
// index.ts (class interceptor)
this.instance.interceptors.request.use(
(res: AxiosRequestConfig) => { console.log('Global request interceptor'); return res },
(err: any) => err,
)
this.instance.interceptors.response.use(
(res: AxiosResponse) => { console.log('Global response interceptor'); return res.data },
(err: any) => err,
)Response data is automatically unwrapped from .data because most APIs return payloads under that property.
Instance Interceptor
To allow per‑instance customization, a RequestInterceptors interface is introduced and merged into a new RequestConfig type that extends AxiosRequestConfig :
// types.ts
export interface RequestInterceptors {
// request interceptor
requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig
requestInterceptorsCatch?: (err: any) => any
// response interceptor
responseInterceptors?:
(config: T) => T
responseInterceptorsCatch?: (err: any) => any
}
export interface RequestConfig extends AxiosRequestConfig {
interceptors?: RequestInterceptors
}The constructor stores the provided interceptors and registers them after the global ones, ensuring the execution order: instance request → class request → instance response → class response.
API‑Level Interceptor
When calling request() , the method checks if the supplied RequestConfig contains its own interceptors and applies them before sending the request and after receiving the response.
Request Method Wrapping
A helper ywzRequest is exported to simplify API calls. It defaults to GET, automatically maps data to params for GET requests, and returns a typed Promise :
// src/server/index.ts
interface YWZRequestConfig
extends RequestConfig { data?: D }
interface YWZResponse
{ code: number; message: string; data: T }
const ywzRequest =
(config: YWZRequestConfig
) => {
const { method = 'GET' } = config
if (method === 'GET' || method === 'get') {
config.params = config.data
}
return request.request
>(config)
}
export default ywzRequestRequest Cancellation
To prevent duplicate or unwanted requests, the wrapper maintains two collections: requestUrlList and cancelRequestSourceList . When a request is created, its URL and a cancel token are stored; after the request settles, both entries are removed.
// index.ts (cancellation setup)
request
(config: RequestConfig): Promise
{
if (config.interceptors?.requestInterceptors) {
config = config.interceptors.requestInterceptors(config)
}
const url = config.url
if (url) {
this.requestUrlList?.push(url)
config.cancelToken = new axios.CancelToken(c => {
this.cancelRequestSourceList?.push({ [url]: c })
})
}
return this.instance.request
(config)
.then(res => {
if (config.interceptors?.responseInterceptors) {
res = config.interceptors.responseInterceptors
(res)
}
return res
})
.finally(() => { url && this.delUrl(url) })
}Utility methods getSourceIndex , delUrl , cancelRequest , and cancelAllRequest provide fine‑grained control over single or multiple pending requests.
Testing
A sample Vue component demonstrates how to call the wrapped request, apply per‑API interceptors, and trigger cancellation via UI buttons. The console output shows the order of interceptor execution and confirms that cancellation works as expected.
Conclusion
The article ends with a call for feedback and provides the GitHub repository link for the full project. Readers are encouraged to star, fork, or contribute to the code.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.