Using Axios to encapsulate backend API calls in a TypeScript project
Wrapping axios? Under TypeScript, it's just adding some type declarations—calling that innovation is a stretch. Interceptors for automatic token addition and 401 redirects? That's just standard procedure. Unified return values? Back to that backend routine again, what a hassle.
目录10 个章节
Preface
Originally, I wanted to share my Next.js development notes, but then I realized they involve too many things, so I decided to split them up~
This article documents the process of encapsulating axios in a TypeScript project. Previously, while developing StarBlog-Admin, I had already done an encapsulation, but that was in JavaScript, which is somewhat different from TypeScript.
Additionally, while following the Next.js documentation for development, I noticed that the official docs recommend using @tanstack/react-query to encapsulate request operations. After a quick glance at the docs, it looks quite promising, and I plan to implement it in my project.
Define Configuration
First, create a global configuration file: src/utilities/global.ts
export default class Global {
static baseUrl = process.env.NEXT_PUBLIC_BASE_URL
}
This is in a Next.js project, so you can use the environment variables specified by Next. For other projects, you can adjust this as needed.
Encapsulation Auth
The authentication part is somewhat related to axios, but not very much. However, since it's needed in the axios encapsulation, I'll include it here as well.
Create the src/utilities/auth.ts file
/**
* Login Information
*/
export interface LoginProps {
token: string
username: string
expiration: string
}
/**
* Authentication Authorization Utility Class
*/
export default abstract class Auth {
static get storage(): Storage | null {
if (typeof window !== 'undefined') {
return window.localStorage
}
return null
}
/**
* Check if logged in
* @return boolean
*/
public static isLogin() {
let token = this.storage?.getItem('token')
let userName = this.storage?.getItem('user')
if (!token || token.length === 0) return false
if (!userName || userName.length === 0) return false
return !this.isExpired();
}
/**
* Check if login has expired
* @return boolean
*/
public static isExpired = () => {
let expiration = this.storage?.getItem('expiration')
if (expiration) {
let now = new Date()
let expirationTime = new Date(expiration)
if (now > expirationTime) return true
}
return false
}
/**
* Read saved token
* @return string
*/
public static getToken = () => {
return this.storage?.getItem('token')
}
/**
* Save login information
* @param props
*/
public static login = (props: LoginProps) => {
this.storage?.setItem('token', props.token)
this.storage?.setItem('user', props.username)
this.storage?.setItem('expiration', props.expiration)
}
/**
* Logout
*/
public static logout = () => {
this.storage?.removeItem('token')
this.storage?.removeItem('user')
this.storage?.removeItem('expiration')
}
}
I've placed all authentication-related logic in the Auth class.
To work smoothly in Next.js, some special handling is required. For example, I added a storage property that checks for the existence of window before reading.
Encapsulating Axios
All code related to the API is placed in the src/services directory.
Create the src/services/api.ts file. The code is quite long, so it will be introduced in sections. As you can see, all configurations have additional settings compared to the previous JavaScript version, making them very friendly for IDE auto-completion.
First, import the necessary modules.
import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults} from "axios";
import Global from '@/utilities/global'
import Auth from "@/utilities/auth";
Axios Configuration
Define the configuration for axios.
const config: CreateAxiosDefaults<any> = {
method: 'get',
// Base URL prefix
baseURL: `${Global.baseUrl}/`,
// Request header information
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
// Parameters
data: {},
// Set the timeout duration
timeout: 10000,
// Send credentials
withCredentials: true,
// Response data type
responseType: 'json'
}
Standardized API Responses
Setting up standardized API responses - this is the same pattern I implemented in the StarBlog backend. It has become my standard approach for backend responses. I've also released the CodeLab.Share NuGet package, which allows quick integration of this standardized response component.
// Standardized API Responses
export interface ApiResponse {
data: any
errorData: any
message: string
statusCode: number
successful: boolean
}
Define ApiClient
Finally, we define the ApiClient class, which is a bit reminiscent of C#'s HttpClient.
It uses Axios interceptors to add authentication information to the headers when making requests and to check for errors in responses. If there is a 401 Unauthorized error, it redirects to the login page.
export class ApiClient {
private readonly api: AxiosInstance
constructor() {
this.api = axios.create({
...config,
})
this.api.interceptors.request.use(
config => {
config.headers.Authorization = `Bearer ${Auth.getToken()}`
return config
},
error => {
return error
})
this.api.interceptors.response.use(
response => {
return response
},
error => {
let reason = error
if (error && error.response) {
if (error.response.data) {
reason = error.response.data
if (!reason.message) reason.message = error.message
}
if (error.response.status === 401) {
location.href = '/login'
}
}
return Promise.reject(reason)
}
)
}
public request(options: AxiosRequestConfig): Promise<ApiResponse> {
return new Promise((resolve, reject) => {
this.api(options).then((res: AxiosResponse<ApiResponse>) => {
resolve(res.data)
return false
}).catch(error => {
reject(error)
})
})
}
}
export const api = new ApiClient()
export default api
The code is simpler than what I had in StarBlog-Admin. I aim to implement the required functionality with as little code as possible.
Writing Specific Interface Calls
All my interface calls are written as services (this follows backend development thinking).
Here, using the SMS sending interface as an example.
Create the src/services/common.ts file, import the ApiClient object from the api.ts file we just defined, and simply call the request method.
The parameter type is AxiosRequestConfig, and I'm not making any modifications to axios itself, which I feel is more comfortable than using the customized interface from Antd Pro previously.
import {api} from './api'
export class SmsChannel {
static local = 0
static aliyun = 1
static tencent = 2
}
export default abstract class CommonService {
public static getSmsCode(phone: string, channel: number = SmsChannel.local) {
return api.request({
url: `api/common/getSmsCode`,
params: {phone, channel}
})
}
}
Summary
After this encapsulation, it's much more comfortable than the previous StarBlog-Admin. Unfortunately, that earlier project used vue2.x and seems to not support TypeScript.
That's it for now; most of the content is still in the next.js development notes.
References
_EOF_
Using Axios to encapsulate backend API calls in a TypeScript project
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
主流 nodejs 包管理器 pnpm vs bun vs npm vs yarn 简单横评
pnpm还真是会玩空间魔术?单项目里它领先优势就这么点?Node.js 20把npm喂肥了,现在谁还敢说npm是废物?这测试结果真是让人摸不着头脑。
2025-08-27 · Web前端 · 约 1 分钟
纯前端实现词云展示+附微博热搜词云Demo代码
前言 最近工作中做了几个数据可视化大屏项目,其中也有用到了词云展示,以前做词云都是用python库来生成图片显示的,这次用了纯前端的实现~~(Ctrl+V真好用)~~,同时顺手做个微博热搜的词云然后记录一下~ 依赖 echarts 4.x echarts-wordcloud 1.1.3 tips:echarts-wordcloud现在有2.0和1.x两个版本,2.0对应echarts 5.x版本
2021-12-18 · Web前端 · 约 1 分钟
Vue2.x项目整合ExceptionLess监控
前言 一直以来我们都是用Sentry做项目监控,不过前段时间我们的Sentry坏掉了~~(我搞坏的)~~ 但监控又是很有必要的,在sentry修好之前,我想先寻找一个临时的替代方案,同时发现网上关于ExceptionLess的资料少得可怜,ExceptionLess官方的文档也不是很完善,翻了好久文档和源码,于是有了本文…… 关于ExceptionLess 写.NetCore的同学应该不会陌生,这
2022-03-23 · Web前端 · 约 1 分钟
魔改editormd组件,优化ToC渲染效果
前言 我的StarBlog博客目前使用 editor.md 组件在前端渲染markdown文章,但这个组件自动生成的ToC(内容目录)不是很美观,我之前魔改过一个树形组件 BootStrap-TreeView,所以就想要用这个树形组件来展示ToC。 原本的效果是这样的 image-20221020112752560 我魔改完的效果 image-20221020112914518 先分析一波 首先看
2022-10-20 · Web前端 · 约 1 分钟
讨论
共 0 条加载评论中…