Chapter 12: Framework Integration and Practical Applications
Haiyue
15min
Chapter 12: Framework Integration and Practical Applications
Learning Objectives
- Master integrating Axios in Vue.js
- Learn to use Axios in React
- Understand applications in Node.js
- Implement state management integration
- Build complete API service layers
12.1 Vue.js Integration
Vue 3 + Composition API
// composables/useApi.js
import { ref, reactive } 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 in 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 users:', err)
}
})
</script>
Pinia State Management Integration
// stores/user.js
import { defineStore } from 'pinia'
import { useApi } from '@/composables/useApi'
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 } 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 } from 'react'
import axios from 'axios'
const ApiContext = createContext()
export function ApiProvider({ children, baseURL = '/api' }) {
const client = axios.create({
baseURL,
timeout: 10000
})
// Setup 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 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 get users: ${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 get 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
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 error
console.error('API error:', errorInfo)
// Handle differently based on error type
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: 'Invalid request parameters', canRetry: false }
case 401:
return { message: 'Please login again', canRetry: false, requiresAuth: true }
case 403:
return { message: 'No permission to access', canRetry: false }
case 404:
return { message: 'Requested resource not found', 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 timeout, 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:
- Using Axios with Composition API and Pinia in Vue.js
- Using Axios through custom Hooks and Context in React
- Axios applications in Node.js backend environment
- Building complete API service layer architecture
- Unified error handling and recovery mechanisms
Complete Axios Course Summary
After 12 chapters of systematic learning, we started from Axios basics and gradually progressed to advanced applications, finally completing comprehensive Axios HTTP client learning:
Core Skills Mastered
- Basic Skills: HTTP methods, request configuration, response handling, error handling
- Advanced Skills: Interceptor mechanisms, instance configuration, request cancellation, concurrency control
- Advanced Applications: File upload/download, authentication, performance optimization, TypeScript integration
- Practical Applications: Framework integration, enterprise architecture, best practices
Key Features Understanding
- Interceptors provide powerful request/response processing capabilities
- Instantiation supports multi-service and multi-environment configuration
- Comprehensive error handling mechanisms ensure 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
- Comprehensive error recovery and user experience
- Maintainable code architecture and best practices
- Comprehensive testing and monitoring solutions
Axios, as the most important HTTP client library in modern web development, provides us with complete network communication solutions. Mastering this knowledge and skills will provide a solid foundation for building high-quality web applications.
Key Points
- Different frameworks have their own integration best practices
- State management integration simplifies data flow management
- Unified API service layer improves code reusability
- Comprehensive error handling mechanisms enhance user experience
- Continuously learn new API design patterns and best practices