Axios Complete Guide | Promise-Based HTTP Client for JavaScript
이 글의 핵심
Axios is a promise-based HTTP client for JavaScript. It works in both browser and Node.js, providing a clean API for making HTTP requests with interceptors, automatic JSON handling, and request cancellation.
Introduction
Axios is a promise-based HTTP client for the browser and Node.js. It provides a simple, clean API for making HTTP requests with features like interceptors, automatic JSON transformation, and request cancellation.
Why Axios?
Native Fetch:
fetch('https://api.example.com/users')
.then(response => {
if (!response.ok) throw new Error('HTTP error');
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error(error));
With Axios:
axios.get('https://api.example.com/users')
.then(response => console.log(response.data))
.catch(error => console.error(error));
1. Installation
# npm
npm install axios
# yarn
yarn add axios
# CDN (browser)
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
2. Basic Usage
GET Request
const axios = require('axios');
// Simple GET
axios.get('https://api.example.com/users')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
// Async/await
async function getUsers() {
try {
const response = await axios.get('https://api.example.com/users');
console.log(response.data);
} catch (error) {
console.error(error);
}
}
// With query parameters
axios.get('https://api.example.com/users', {
params: {
page: 1,
limit: 10,
}
});
// Request: GET /users?page=1&limit=10
POST Request
// POST with JSON body
axios.post('https://api.example.com/users', {
name: 'Alice',
email: 'alice@example.com',
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
// With headers
axios.post('https://api.example.com/users', {
name: 'Alice',
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123',
}
});
PUT Request
// Update user
axios.put('https://api.example.com/users/123', {
name: 'Alice Updated',
email: 'alice-new@example.com',
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
DELETE Request
// Delete user
axios.delete('https://api.example.com/users/123')
.then(response => console.log('Deleted'))
.catch(error => console.error(error));
// With data
axios.delete('https://api.example.com/users/123', {
data: { reason: 'Account closed' }
});
3. Axios Instance
// Create instance with default config
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// Use instance
api.get('/users'); // GET https://api.example.com/users
api.post('/users', { ... }); // POST https://api.example.com/users
// Multiple instances
const apiV1 = axios.create({ baseURL: 'https://api.example.com/v1' });
const apiV2 = axios.create({ baseURL: 'https://api.example.com/v2' });
4. Request Configuration
axios({
method: 'post',
url: '/users',
baseURL: 'https://api.example.com',
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json',
},
params: {
page: 1,
},
data: {
name: 'Alice',
email: 'alice@example.com',
},
timeout: 5000,
withCredentials: true, // Send cookies
responseType: 'json', // 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
maxRedirects: 5,
validateStatus: (status) => status >= 200 && status < 300,
});
5. Response Schema
const response = await axios.get('/users/123');
console.log(response.data); // Response body
console.log(response.status); // 200
console.log(response.statusText); // "OK"
console.log(response.headers); // Response headers
console.log(response.config); // Request config
console.log(response.request); // XMLHttpRequest
6. Error Handling
try {
const response = await axios.get('/users/123');
console.log(response.data);
} catch (error) {
if (error.response) {
// Server responded with error status
console.error('Status:', error.response.status);
console.error('Data:', error.response.data);
console.error('Headers:', error.response.headers);
} else if (error.request) {
// Request made but no response
console.error('No response:', error.request);
} else {
// Error setting up request
console.error('Error:', error.message);
}
}
// Custom error handling
axios.get('/users/123')
.catch(error => {
if (error.response?.status === 404) {
console.log('User not found');
} else if (error.response?.status === 500) {
console.log('Server error');
} else {
console.log('Unknown error');
}
});
7. Interceptors
Request Interceptors
// Add request interceptor
axios.interceptors.request.use(
(config) => {
// Modify config before request
console.log('Request:', config.method, config.url);
// Add auth token
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
Response Interceptors
// Add response interceptor
axios.interceptors.response.use(
(response) => {
// Transform response data
console.log('Response:', response.status);
return response;
},
async (error) => {
// Handle errors globally
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
// Refresh token
const newToken = await refreshAuthToken();
axios.defaults.headers.common['Authorization'] = `Bearer ${newToken}`;
return axios(originalRequest);
}
return Promise.reject(error);
}
);
Remove Interceptors
const interceptor = axios.interceptors.request.use(config => config);
// Remove later
axios.interceptors.request.eject(interceptor);
8. Request Cancellation
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/users', {
cancelToken: source.token
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('Request canceled:', error.message);
}
});
// Cancel request
source.cancel('Operation canceled by user');
// AbortController (modern)
const controller = new AbortController();
axios.get('/users', {
signal: controller.signal
});
// Cancel
controller.abort();
9. Concurrent Requests
// Multiple requests
const [users, posts, comments] = await Promise.all([
axios.get('/users'),
axios.get('/posts'),
axios.get('/comments'),
]);
console.log(users.data);
console.log(posts.data);
console.log(comments.data);
// With axios.all (deprecated, use Promise.all)
axios.all([
axios.get('/users'),
axios.get('/posts'),
])
.then(axios.spread((users, posts) => {
console.log(users.data);
console.log(posts.data);
}));
10. Form Data
// Multipart form data
const formData = new FormData();
formData.append('name', 'Alice');
formData.append('file', fileInput.files[0]);
axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`Upload: ${percentCompleted}%`);
},
});
// URL-encoded form data
const params = new URLSearchParams();
params.append('name', 'Alice');
params.append('email', 'alice@example.com');
axios.post('/users', params, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
11. Real-World Example: API Client
// api.js
import axios from 'axios';
const api = axios.create({
baseURL: process.env.REACT_APP_API_URL || 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// Request interceptor
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Response interceptor
api.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// Handle 401 (unauthorized)
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const { data } = await axios.post('/auth/refresh', {
refreshToken: localStorage.getItem('refreshToken'),
});
localStorage.setItem('token', data.token);
api.defaults.headers.common['Authorization'] = `Bearer ${data.token}`;
return api(originalRequest);
} catch (refreshError) {
// Redirect to login
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
// Handle other errors
if (error.response?.status === 500) {
console.error('Server error:', error.response.data);
}
return Promise.reject(error);
}
);
// API methods
export const usersAPI = {
getAll: (params) => api.get('/users', { params }),
getById: (id) => api.get(`/users/${id}`),
create: (data) => api.post('/users', data),
update: (id, data) => api.put(`/users/${id}`, data),
delete: (id) => api.delete(`/users/${id}`),
};
export const postsAPI = {
getAll: (params) => api.get('/posts', { params }),
getById: (id) => api.get(`/posts/${id}`),
create: (data) => api.post('/posts', data),
update: (id, data) => api.put(`/posts/${id}`, data),
delete: (id) => api.delete(`/posts/${id}`),
};
export default api;
12. TypeScript Support
import axios, { AxiosResponse } from 'axios';
interface User {
id: number;
name: string;
email: string;
}
// Typed GET request
const response: AxiosResponse<User> = await axios.get<User>('/users/123');
const user: User = response.data;
// Typed POST request
const createUser = async (userData: Omit<User, 'id'>): Promise<User> => {
const response = await axios.post<User>('/users', userData);
return response.data;
};
// Generic API function
async function fetchData<T>(url: string): Promise<T> {
const response = await axios.get<T>(url);
return response.data;
}
const users = await fetchData<User[]>('/users');
13. Best Practices
1. Use Axios Instance
// Good: centralized config
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
});
// Bad: repeated config
axios.get('https://api.example.com/users', { timeout: 10000 });
axios.post('https://api.example.com/users', data, { timeout: 10000 });
2. Global Error Handling
api.interceptors.response.use(
response => response,
error => {
// Log errors
console.error('API Error:', error);
// Show toast notification
showErrorToast(error.response?.data?.message);
return Promise.reject(error);
}
);
3. Request Retry Logic
const axiosRetry = require('axios-retry');
axiosRetry(axios, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (error) => {
return axiosRetry.isNetworkOrIdempotentRequestError(error) ||
error.response?.status === 429;
},
});
4. Timeout Configuration
const api = axios.create({
timeout: 10000, // 10 seconds
});
// Or per request
axios.get('/users', { timeout: 5000 });
14. Debugging
// Enable debug logging
axios.interceptors.request.use(config => {
console.log('→', config.method?.toUpperCase(), config.url);
return config;
});
axios.interceptors.response.use(response => {
console.log('←', response.status, response.config.url);
return response;
});
// Log full request/response
axios.get('/users')
.then(response => {
console.log('Request:', response.config);
console.log('Response:', response);
});
Summary
Axios is the go-to HTTP client for JavaScript:
- Promise-based API with async/await
- Interceptors for global request/response handling
- Automatic JSON transformation
- Request cancellation support
- Works everywhere (browser + Node.js)
Key Takeaways:
- Use axios instances for configuration
- Leverage interceptors for auth and errors
- Handle errors with try/catch
- Cancel requests when needed
- TypeScript for type safety
Next Steps:
- Build Express API
- Learn Fetch API
- Handle JWT Authentication
Resources: