Frontend Development 14 min read

Comprehensive Guide to Encapsulating API Requests with Axios and TypeScript

This article explains why and how to wrap asynchronous API calls in a reusable TypeScript utility using Axios, covering request flow analysis, interceptor design, unified GET/POST/PUT/DELETE helpers, development order, and complete source code examples for a maintainable frontend architecture.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Comprehensive Guide to Encapsulating API Requests with Axios and TypeScript

Introduction (Why Build)

In modern frontend projects, asynchronous API calls are unavoidable, and wrapping these calls becomes a mandatory skill. The author discovered that many teammates were using raw axios.post statements without any abstraction, which leads to duplicated code and maintenance headaches as the number of requests grows.

axios.post(`/api/xxxx/xxxx?xxx=${xxx}`, { ...data })
  .then((result) => {
    if (result.errno) {
      // handle error
    } else {
      // handle success
    }
  })
  .catch((err) => {
    // handle network error
  })

Demo Effect

const [e, r] = await api.getUserInfo(userid)
if (!e && r) this.userInfo = r.data.userinfo

The final implementation aims to provide a clean, type‑safe API request tool that returns a tuple [err, result] for both success and failure cases.

Clear Thinking – What We Need to Do

Before coding, the author spent two hours drawing a request flow diagram to identify two major concerns:

Basic request process (pre‑intercept, actual request, post‑intercept)

Interceptors (request and response handling)

Basic Request Process

The flow can be split into three stages:

Before request interception

Actual HTTP request

After response interception

These stages further divide into handling a single endpoint and handling common logic for all endpoints (GET, POST, PUT, DELETE).

Interceptors

Two categories of interceptors are defined:

Request interceptor – adjust headers, attach authentication token, etc.

Response interceptor – unified error handling for network errors, authentication errors, and generic business errors.

Unified Call Order

The development follows a strict order to avoid uncertainty:

Common handling for all GET requests

Request interceptor

Response interceptor

Specific handling for individual endpoints

Packaging logic

Common handling for POST/PUT/DELETE

Implementation Details

GET Helper

type Fn = (data: FcResponse
) => unknown
interface IAnyObj { [index: string]: unknown }
interface FcResponse
{ errno: string; errmsg: string; data: T }

const get =
(url: string, params: IAnyObj = {}, clearFn?: Fn): Promise<[any, FcResponse
| undefined]> =>
  new Promise((resolve) => {
    axios
      .get(url, { params })
      .then((result) => {
        let res: FcResponse
if (clearFn !== undefined) {
          res = clearFn(result.data) as unknown as FcResponse
} else {
          res = result.data as FcResponse
}
        resolve([null, res])
      })
      .catch((err) => {
        resolve([err, undefined])
      })
  })

Request Interceptor

const handleRequestHeader = (config) => {
  config['xxxx'] = 'xxx'
  return config
}

const handleAuth = (config) => {
  config.header['token'] = localStorage.getItem('token') || token || ''
  return config
}

axios.interceptors.request.use((config) => {
  config = handleRequestHeader(config)
  config = handleAuth(config)
  return config
})

Response Interceptor and Error Handlers

const handleNetworkError = (errStatus) => {
  let errMessage = '未知错误'
  if (errStatus) {
    switch (errStatus) {
      case 400: errMessage = '错误的请求'; break
      case 401: errMessage = '未授权,请重新登录'; break
      case 403: errMessage = '拒绝访问'; break
      case 404: errMessage = '请求错误,未找到该资源'; break
      case 405: errMessage = '请求方法未允许'; break
      case 408: errMessage = '请求超时'; break
      case 500: errMessage = '服务器端出错'; break
      case 501: errMessage = '网络未实现'; break
      case 502: errMessage = '网络错误'; break
      case 503: errMessage = '服务不可用'; break
      case 504: errMessage = '网络超时'; break
      case 505: errMessage = 'http版本不支持该请求'; break
      default: errMessage = `其他连接错误 --${errStatus}`
    }
  } else {
    errMessage = `无法连接到服务器!`
  }
  message.error(errMessage)
}

const handleAuthError = (errno) => {
  const authErrMap = {
    '10031': '登录失效,需要重新登录',
    '10032': '您太久没登录,请重新登录~',
    '10033': '账户未绑定角色,请联系管理员绑定角色',
    '10034': '该用户未注册,请联系管理员注册用户',
    '10035': 'code 无法获取对应第三方平台用户',
    '10036': '该账户未关联员工,请联系管理员做关联',
    '10037': '账号已无效',
    '10038': '账号未找到',
  }
  if (authErrMap.hasOwnProperty(errno)) {
    message.error(authErrMap[errno])
    logout()
    return false
  }
  return true
}

const handleGeneralError = (errno, errmsg) => {
  if (errno !== '0') {
    message.error(errmsg)
    return false
  }
  return true
}

axios.interceptors.response.use(
  (response) => {
    if (response.status !== 200) return Promise.reject(response.data)
    handleAuthError(response.data.errno)
    handleGeneralError(response.data.errno, response.data.errmsg)
    return response
  },
  (err) => {
    handleNetworkError(err.response.status)
    return Promise.reject(err.response)
  }
)

POST/PUT/DELETE Helpers

export const post =
(url: string, data: IAnyObj, params: IAnyObj = {}): Promise<[any, FcResponse
| undefined]> => {
  return new Promise((resolve) => {
    axios
      .post(url, data, { params })
      .then((result) => resolve([null, result.data as FcResponse
]))
      .catch((err) => resolve([err, undefined]))
  })
}
// Put / Del are analogous

Unified Export

import { userApi } from "./path/user"
import { shoporderApi } from "./path/shoporder"

export const api = {
  ...userApi,
  ...shoporderApi,
}

With this structure, developers can call any endpoint via api.getUserInfo(id) or api.getShoporderList() , benefiting from consistent error handling, type safety, and reduced boilerplate across the entire frontend codebase.

frontendTypeScriptAxiosHTTPAPIInterceptorRequest
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.