Chapter 12: Framework Integration and Practical Applications
9/1/25About 5 min
Chapter 12: Framework Integration and Practical Applications
Learning Objectives
- Master integrating Axios in Vue.js
- Learn to use Axios in React
- Understand its application in Node.js
- Implement state management integration
- Build a complete API service layer
12.1 Vue.js Integration
Vue 3 + Composition API
// composables/useApi.js
import { ref, reactive, readonly } from 'vue'
import axios from 'axios'
export function useApi(baseURL = '/api') {
const loading = ref(false)
const error = ref(null)
const client = axios.create({
baseURL,
timeout: 10000
})
// Request interceptor
client.interceptors.request.use(
config => {
loading.value = true
error.value = null
return config
},
err => {
loading.value = false
error.value = err
return Promise.reject(err)
}
)
// Response interceptor
client.interceptors.response.use(
response => {
loading.value = false
return response
},
err => {
loading.value = false
error.value = err
return Promise.reject(err)
}
)
const get = async (url, config = {}) => {
try {
const response = await client.get(url, config)
return response.data
} catch (err) {
throw err
}
}
const post = async (url, data, config = {}) => {
try {
const response = await client.post(url, data, config)
return response.data
} catch (err) {
throw err
}
}
return {
loading: readonly(loading),
error: readonly(error),
get,
post,
put: (url, data, config) => client.put(url, data, config),
delete: (url, config) => client.delete(url, config),
client
}
}
// Using it in a component
// UserList.vue
<template>
<div>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<ul v-else>
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useApi } from '@/composables/useApi'
const { loading, error, get } = useApi()
const users = ref([])
onMounted(async () => {
try {
users.value = await get('/users')
} catch (err) {
console.error('Failed to fetch user list:', err)
}
})
</script>
Pinia State Management Integration
// stores/user.js
import { defineStore } from 'pinia'
import { useApi } from '@/composables/useApi'
import { ref } from 'vue'
export const useUserStore = defineStore('user', () => {
const { get, post, put, delete: del } = useApi()
const users = ref([])
const currentUser = ref(null)
const loading = ref(false)
const fetchUsers = async () => {
loading.value = true
try {
users.value = await get('/users')
} catch (error) {
console.error('Failed to fetch users:', error)
} finally {
loading.value = false
}
}
const createUser = async (userData) => {
try {
const newUser = await post('/users', userData)
users.value.push(newUser)
return newUser
} catch (error) {
console.error('Failed to create user:', error)
throw error
}
}
const updateUser = async (id, userData) => {
try {
const updatedUser = await put(`/users/${id}`, userData)
const index = users.value.findIndex(u => u.id === id)
if (index > -1) {
users.value[index] = updatedUser
}
return updatedUser
} catch (error) {
console.error('Failed to update user:', error)
throw error
}
}
return {
users,
currentUser,
loading,
fetchUsers,
createUser,
updateUser
}
})
12.2 React Integration
Custom Hook
// hooks/useApi.js
import { useState, useEffect, useCallback } from 'react'
import axios from 'axios'
export function useApi(baseURL = '/api') {
const [client] = useState(() => axios.create({
baseURL,
timeout: 10000
}))
useEffect(() => {
const requestInterceptor = client.interceptors.request.use(
config => config,
error => Promise.reject(error)
)
const responseInterceptor = client.interceptors.response.use(
response => response,
error => {
console.error('API Error:', error)
return Promise.reject(error)
}
)
return () => {
client.interceptors.request.eject(requestInterceptor)
client.interceptors.response.eject(responseInterceptor)
}
}, [client])
return client
}
// hooks/useUsers.js
import { useState, useEffect, useCallback } from 'react'
import { useApi } from './useApi'
export function useUsers() {
const api = useApi()
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const fetchUsers = useCallback(async () => {
setLoading(true)
setError(null)
try {
const response = await api.get('/users')
setUsers(response.data)
} catch (err) {
setError(err)
} finally {
setLoading(false)
}
}, [api])
const createUser = useCallback(async (userData) => {
try {
const response = await api.post('/users', userData)
setUsers(prev => [...prev, response.data])
return response.data
} catch (err) {
setError(err)
throw err
}
}, [api])
useEffect(() => {
fetchUsers()
}, [fetchUsers])
return {
users,
loading,
error,
refetch: fetchUsers,
createUser
}
}
React Context Integration
// context/ApiContext.js
import React, { createContext, useContext, useEffect, useState } from 'react'
import axios from 'axios'
const ApiContext = createContext()
export function ApiProvider({ children, baseURL = '/api' }) {
const [client] = useState(() => axios.create({
baseURL,
timeout: 10000
}))
// Set up interceptors
useEffect(() => {
const token = localStorage.getItem('token')
if (token) {
client.defaults.headers.common['Authorization'] = `Bearer ${token}`
}
const responseInterceptor = client.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
localStorage.removeItem('token')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
return () => {
client.interceptors.response.eject(responseInterceptor)
}
}, [client])
return (
<ApiContext.Provider value={client}>
{children}
</ApiContext.Provider>
)
}
export function useApiClient() {
const client = useContext(ApiContext)
if (!client) {
throw new Error('useApiClient must be used within an ApiProvider')
}
return client
}
12.3 Node.js Backend Integration
Express Middleware
// middleware/apiClient.js
const axios = require('axios')
function createApiClient(baseURL, timeout = 10000) {
const client = axios.create({
baseURL,
timeout,
headers: {
'User-Agent': 'NodeJS-Server/1.0'
}
})
// Request interceptor
client.interceptors.request.use(
config => {
console.log(`Sending request: ${config.method?.toUpperCase()} ${config.url}`)
return config
},
error => {
console.error('Request configuration error:', error)
return Promise.reject(error)
}
)
// Response interceptor
client.interceptors.response.use(
response => {
console.log(`Request successful: ${response.status} ${response.config.url}`)
return response
},
error => {
console.error(`Request failed: ${error.response?.status} ${error.config?.url}`)
return Promise.reject(error)
}
)
return client
}
// Create clients for different services
const userServiceClient = createApiClient('http://user-service:3001')
const orderServiceClient = createApiClient('http://order-service:3002')
module.exports = {
userServiceClient,
orderServiceClient
}
Service Proxy Layer
// services/UserService.js
const { userServiceClient } = require('../middleware/apiClient')
class UserService {
async getUsers(page = 1, limit = 10) {
try {
const response = await userServiceClient.get('/users', {
params: { page, limit }
})
return response.data
} catch (error) {
throw new Error(`Failed to fetch user list: ${error.message}`)
}
}
async getUserById(id) {
try {
const response = await userServiceClient.get(`/users/${id}`)
return response.data
} catch (error) {
if (error.response?.status === 404) {
return null
}
throw new Error(`Failed to fetch user: ${error.message}`)
}
}
async createUser(userData) {
try {
const response = await userServiceClient.post('/users', userData)
return response.data
} catch (error) {
if (error.response?.status === 400) {
throw new Error(`Failed to create user: ${error.response.data.message}`)
}
throw new Error(`Failed to create user: ${error.message}`)
}
}
}
module.exports = new UserService()
12.4 Complete Application Example
Frontend-Backend Separation Architecture
// Frontend - API Service Layer
// services/ApiService.js
import axios from 'axios'
class ApiService {
constructor() {
this.client = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL || '/api',
timeout: 10000
})
this.setupInterceptors()
}
setupInterceptors() {
// Request interceptor - add authentication
this.client.interceptors.request.use(config => {
const token = this.$store.getters['auth/token']
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// Response interceptor - handle errors
this.client.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
this.$store.dispatch('auth/logout')
this.$router.push('/login')
}
return Promise.reject(error)
}
)
}
// User-related APIs
users = {
list: (params) => this.client.get('/users', { params }),
get: (id) => this.client.get(`/users/${id}`),
create: (data) => this.client.post('/users', data),
update: (id, data) => this.client.put(`/users/${id}`, data),
delete: (id) => this.client.delete(`/users/${id}`)
}
// Order-related APIs
orders = {
list: (params) => this.client.get('/orders', { params }),
get: (id) => this.client.get(`/orders/${id}`),
create: (data) => this.client.post('/orders', data),
update: (id, data) => this.client.put(`/orders/${id}`, data),
cancel: (id) => this.client.post(`/orders/${id}/cancel`)
}
}
export default new ApiService()
Error Boundaries and Recovery
// utils/errorHandler.js
export class ApiErrorHandler {
static handle(error, context = {}) {
const errorInfo = {
url: error.config?.url,
method: error.config?.method,
status: error.response?.status,
message: error.message,
context
}
// Log the error
console.error('API Error:', errorInfo)
// Handle different error types
if (error.response) {
return this.handleResponseError(error.response, context)
} else if (error.request) {
return this.handleNetworkError(error, context)
} else {
return this.handleConfigError(error, context)
}
}
static handleResponseError(response, context) {
const { status, data } = response
switch (status) {
case 400:
return { message: 'Bad request parameters', canRetry: false }
case 401:
return { message: 'Please log in again', canRetry: false, requiresAuth: true }
case 403:
return { message: 'No permission to access', canRetry: false }
case 404:
return { message: 'The requested resource does not exist', canRetry: false }
case 500:
return { message: 'Server error, please try again later', canRetry: true }
default:
return { message: data?.message || 'Request failed', canRetry: true }
}
}
static handleNetworkError(error, context) {
if (error.code === 'ECONNABORTED') {
return { message: 'Request timed out, please try again later', canRetry: true }
}
return { message: 'Network connection failed, please check your network', canRetry: true }
}
}
Chapter Summary
Through this chapter, we have mastered:
- Integrating Axios in Vue.js using Composition API and Pinia
- Using Axios in React through custom hooks and Context
- Axios application in a Node.js backend environment
- Building a complete API service layer architecture
- Unified error handling and recovery mechanisms
Complete Axios Course Summary
After 12 chapters of systematic learning, we started from the basics of Axios, gradually delved into advanced applications, and finally completed the comprehensive study of the Axios HTTP client:
Core Skills Mastered
- Basic Skills: HTTP methods, request configuration, response handling, error handling
- Advanced Skills: Interceptor mechanism, instance configuration, request cancellation, concurrency control
- Advanced Applications: File upload/download, authentication, performance optimization, TypeScript integration
- Practical Applications: Framework integration, enterprise-level architecture, best practices
Key Feature Understanding
- Interceptors provide powerful request and response handling capabilities
- Instantiation supports multi-service and multi-environment configurations
- A complete error handling mechanism ensures application stability
- TypeScript integration provides type safety guarantees
- Framework integration adapts to different development environments
Production-Level Practices
- Secure authentication mechanisms and token management
- Efficient caching and performance optimization strategies
- Complete error recovery and user experience
- Maintainable code architecture and best practices
- Comprehensive testing and monitoring solutions
As the most important HTTP client library in modern web development, Axios provides us with a complete network communication solution. Mastering this knowledge and these skills will provide a solid foundation for building high-quality web applications.
Key Takeaways
- Different frameworks have their own best practices for integration
- State management integration simplifies data flow management
- A unified API service layer improves code reusability
- A complete error handling mechanism enhances user experience
- Continuously learn new API design patterns and best practices