I Removed All the Try-Catch Blocks from the Project, Boss: 6
🐞 Common Bug Pattern in API Calls
Many developers have unintentionally written bugs like this (not exactly like the image 👇):

Typical `try–catch` Example
try {
const res = await api.getUser()
console.log('✅ User info', res)
} catch (err) {
console.error('❌ Request failed', err)
}At first glance, this code seems fine — but there are hidden issues.
---
⚠️ Problems with the Approach
- Too verbose: You need a `try–catch` for every API call.
- Scattered error handling: No central control over how errors are processed.
- Bloated code: Harder to maintain, leads to code smell 💨.
---
🎯 Goal: Safe Request Wrapper
We’ll build a safe request utility that doesn’t throw exceptions, allowing cleaner calls like:
const [err, data] = await safeRequest(api.getUser(1))
if (err) return showError(err)
console.log('✅ User info:', data)No `try–catch` clutter, but both error and data are still accessible.
---
🧩 Step 1: Wrap the Axios Instance
// src/utils/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus'
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
})
// 🧱 Request Interceptor
service.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
},
(error) => Promise.reject(error)
)---
🧩 Step 2: Add a Response Interceptor
// 🧱 Response Interceptor
service.interceptors.response.use(
(response) => {
const res = response.data
if (res.code !== 0) {
ElMessage.error(res.message || 'Request failed')
return Promise.reject(new Error(res.message || 'Request failed'))
}
return res.data
},
(error) => {
ElMessage.error(error.message || 'Network error')
return Promise.reject(error)
}
)
export default serviceInterceptor Benefits:
- ✅ Unified token handling
- ✅ Centralized error messaging
- ✅ Business logic always gets clean, prepared data
---
🧩 Step 3: Implement `safeRequest`
// src/utils/safeRequest.js
export async function safeRequest(promise) {
try {
const data = await promise
return [null, data] // ✅ success: [null, data]
} catch (err) {
return [err, null] // ❌ failure: [err, null]
}
}Why This Works
It wraps any Promise into a soft `[error, data]` response — no unhandled exceptions.
---
🧩 Step 4: Create an API Module
// src/api/user.js
import request from '@/utils/request'
export const userApi = {
getUser(id) {
return request.get(`/user/${id}`)
},
updateUser(data) {
return request.put('/user', data)
},
}---
🧩 Step 5: Cleaner Calls in the Business Layer
import { ref, onMounted } from 'vue'
import { userApi } from '@/api/user'
import { safeRequest } from '@/utils/safeRequest'
const user = ref(null)
onMounted(async () => {
const [err, data] = await safeRequest(userApi.getUser(1))
if (err) return showError(err)
console.log('✅ User info:', data)
})
Result:
- No repeated `try–catch` blocks
- Clear data logic
- Errors handled gracefully without breaking flow
---
🚀 Extra Optimization: Auto Error Notification
// src/utils/safeRequest.js
import { ElMessage } from 'element-plus'
export async function safeRequest(promise, { showError = true } = {}) {
try {
const data = await promise
return [null, data]
} catch (err) {
if (showError) {
ElMessage.error(err.message || 'Request failed')
}
return [err, null]
}
}Example Usage
const [err, data] = await safeRequest(userApi.getUser(1), { showError: false })This lets you disable errors for "silent" requests.
---
🧠 Bonus: TypeScript Support
export async function safeRequest(
promise: Promise
): Promise<[Error | null, T | null]> {
try {
const data = await promise
return [null, data]
} catch (err) {
return [err as Error, null]
}
}Example
const [err, user] = await safeRequest(userApi.getUser(1))
if (user) console.log(user.name) // ✅ Auto type suggestion---
🌐 Why It Matters in Larger Projects
This pattern is especially useful for complex workflows — e.g., AI-powered content publishing across multiple platforms.
Platforms like AiToEarn use similar techniques to ensure stable API calls and centralized error handling when publishing to Douyin, Kwai, WeChat, Bilibili, Xiaohongshu, Facebook, Instagram, LinkedIn, Threads, YouTube, Pinterest, and X (Twitter).
For more details, check AiToEarn documentation or explore the GitHub repo.
---
✅ Summary:
- Interceptors unify request/response handling
- `safeRequest` eliminates repetitive `try–catch`
- Modular API calls keep business logic clean
- Optional auto-notification and TypeScript typing make it scalable
---
Do you want me to also add a batch API safe handling example using this pattern? That would show how to use it for multiple concurrent requests efficiently.