HTTP Clients: Axios vs Fetch vs Got
Learn: HTTP Clients: Axios vs Fetch vs Got
Welcome to TopperBlog! 👋
I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.
🎯 What I Write About:
• AI/ML Engineering & LLMs
• Web3 & Blockchain Development
• System Design & Architecture
• Interview Preparation (FAANG)
• Freelancing & Remote Work
• Modern Tech Stacks (Next.js, React, Rust, TypeScript)
• Performance Optimization & Best Practices
💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.
📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.
🌐 Let's connect and grow together in this amazing tech journey!
#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering
HTTP Clients: Axios vs Fetch vs Got
Problem
Modern JavaScript applications need to make HTTP requests to APIs and servers. Developers must choose between multiple options: the native Fetch API, Axios library, and Got library. Each has different strengths, weaknesses, and use cases.
Solution
Understanding the key differences helps you select the right tool:
- Fetch: Native browser/Node.js API, minimal overhead, requires manual handling
- Axios: Feature-rich, automatic transformations, great DX, extra bundle size
- Got: Node.js focused, streams support, retries built-in, lightweight
Detailed Comparison
1. Fetch API
Pros:
- Native to browsers and Node.js 18+
- No dependencies
- Lightweight
- Modern Promise-based API
Cons:
- No request/response interceptors
- Manual JSON serialization
- No built-in timeout
- No automatic retries
- Verbose error handling
// Basic GET request
async function fetchExample() {
try {
const response = await fetch('https://api.example.com/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch error:', error);
}
}
// POST with headers and body
async function fetchPost() {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify({ name: 'John', email: 'john@example.com' })
});
return response.json();
}
// Timeout implementation (manual)
function fetchWithTimeout(url, options = {}, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
}
// Usage
fetchWithTimeout('https://api.example.com/users', {}, 3000)
.then(res => res.json())
.catch(err => console.error(err));
2. Axios
Pros:
- Request/response interceptors
- Automatic JSON transformation
- Request cancellation
- Timeout support built-in
- Works in browser and Node.js
- Great error handling
- Request/response transformation
Cons:
- Additional dependency
- Larger bundle size (~13KB)
- Overkill for simple requests
import axios from 'axios';
// Create instance with defaults
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json'
}
});
// Request interceptor
apiClient.interceptors.request.use(
config => {
config.headers.Authorization = `Bearer ${getToken()}`;
console.log('Request:', config);
return config;
},
error => Promise.reject(error)
);
// Response interceptor
apiClient.interceptors.response.use(
response => {
console.log('Response:', response.data);
return response.data;
},
error => {
if (error.response?.status === 401) {
// Handle unauthorized
refreshToken();
}
return Promise.reject(error);
}
);
// GET request
async function getUsers() {
try {
const users = await apiClient.get('/users');
return users;
} catch (error) {
console.error('Error fetching users:', error.message);
}
}
// POST request
async function createUser(userData) {
try {
const response = await apiClient.post('/users', userData);
return response;
} catch (error) {
if (error.response) {
console.error('Server error:', error.response.status);
} else if (error.request) {
console.error('No response received');
} else {
console.error('Error:', error.message);
}
}
}
// Request cancellation
const controller = new AbortController();
async function fetchWithCancel() {
try {
const response = await apiClient.get('/users', {
signal: controller.signal
});
return response;
} catch (error) {
if (error.name === 'CanceledError') {
console.log('Request cancelled');
}
}
}
// Cancel request
controller.abort();
// Parallel requests
async function fetchMultiple() {
try {
const [users, posts] = await Promise.all([
apiClient.get('/users'),
apiClient.get('/posts')
]);
return { users, posts };
} catch (error) {
console.error('Error:', error);
}
}
3. Got
Pros:
- Lightweight and fast
- Built-in retry logic
- Stream support
- Hooks system
- Pagination support
- Better for Node.js
- Smaller bundle size (~5KB)
Cons:
- Node.js only (not browser)
- Smaller ecosystem
- Less popular than Axios
import got from 'got';
// Create instance with defaults
const apiClient = got.extend({
prefixUrl: 'https://api.example.com',
timeout: { request: 5000 },
headers: {
'user-agent': 'MyApp/1.0'
},
retry: { limit: 2 },
hooks: {
beforeRequest: [
options => {
options.headers.authorization = `Bearer ${getToken()}`;
}
],
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
refreshToken();
return retryWithMergedOptions({ headers: { authorization: `Bearer ${getToken()}` } });
}
return response;
}
]
}
});
// GET request
async function getUsers() {
try {
const users = await apiClient.get('users').json();
return users;
} catch (error) {
console.error('Error:', error.message);
}
}
// POST request
async function createUser(userData) {
try {
const response = await apiClient.post('users', {
json: userData
}).json();
return response;
} catch (error) {
console.error('Error:', error.response?.statusCode);
}
}
// Stream support
async function downloadFile(url, destination) {
try {
const stream = got.stream(url);
stream.pipe(fs.createWriteStream(destination));
stream.on('error', error => {
console.error('Stream error:', error);
});
} catch (error) {
console.error('Error:', error);
}
}
// Pagination
async function getAllUsers() {
try {
const users = [];
for await (const item of apiClient.paginate('users', {
pagination: { limit: 10 }
})) {
users.push(item);
}
return users;
} catch (error) {
console.error('Error:', error);
}
}
// Retry with exponential backoff
const response = await apiClient.get('users', {
retry: {
limit: 3,
methods: ['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE'],
statusCodes: [408, 413, 429, 500, 502, 503, 504],
errorCodes: ['ETIMEDOUT', 'ECONNRESET', 'EADDRINUSE', 'ECONNREFUSED', 'EPIPE', 'ENOTFOUND', 'ENETUNREACH', 'EAI_AGAIN']
}
}).json();
Comparison Table
| Feature | Fetch | Axios | Got |
| Environment | Browser/Node.js | Browser/Node.js | Node.js only |
| Bundle Size | 0KB (native) | ~13KB | ~5KB |
| Interceptors | ❌ | ✅ | ✅ (hooks) |
| Timeout | ❌ | ✅ | ✅ |
| Retries | ❌ | ❌ | ✅ |
| Streams | ✅ | ❌ | ✅ |
| JSON Auto | ❌ | ✅ | ✅ |
| Cancellation | ✅ | ✅ | ✅ |
| Learning Curve | Easy | Medium | Medium |
| Popularity | High | Very High | Medium |
Decision Guide
Use Fetch when:
- Building browser-only applications
- Minimizing dependencies
- Simple API calls without complex logic
- You don't need interceptors
Use Axios when:
- Building full-stack applications
- Need interceptors for auth/logging
- Want automatic JSON transformation
- Working with complex request/response handling
- Browser compatibility is important
Use Got when:
- Building Node.js-only applications
- Need built-in retry logic
- Working with streams
- Want lightweight solution
- Building CLI tools or backend services
Real-World Example: API Client
// Universal approach using Axios
class APIClient {
constructor(baseURL, token) {
this.client = axios.create({
baseURL,
timeout: 10000
});
this.client.interceptors.request.use(config => {
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
this.client.interceptors.response.use(
res => res.data,
error => {
const message = error.response?.data?.message || error.message;
throw new Error(message);
}
);
}
async get(endpoint, params) {
return this.client.get(endpoint, { params });
}
async post(endpoint, data) {
return this.client.post(endpoint, data);
}
async put(endpoint, data) {
return this.client.put(endpoint, data);
}
async delete(endpoint) {
return this.client.delete(endpoint);
}
}
// Usage
const api = new APIClient('https://api.example.com', 'token123');
const users = await api.get('/users', { page: 1 });
Conclusion
- Fetch: Best for simple browser applications
- Axios: Best for complex applications needing features
- Got: Best for Node.js backend services
Choose based on your specific needs, environment, and complexity requirements.