JavaScript Fetch API explained simply
What is the Fetch API?
The Fetch API is a modern JavaScript interface for making HTTP requests. It’s built into modern browsers and provides a cleaner, more powerful way to fetch resources from the web compared to the older XMLHttpRequest.
Think of it like this: if you want to get data from a website or send data to a server, the Fetch API is your tool. It’s like having a messenger that can go to any URL, ask for information, and bring it back to your JavaScript code.
Why Use Fetch API?
- Promise-based: Works seamlessly with async/await
- Built-in: No need to install external libraries
- Modern: Better error handling and more features
- Flexible: Supports all HTTP methods (GET, POST, PUT, DELETE, etc.)
Basic Usage
The simplest way to use fetch is to make a GET request:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Or using async/await (cleaner syntax):
async function getData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
Making Different Types of Requests
GET Request (Default)
fetch('https://api.example.com/users')
.then(response => response.json())
.then(users => console.log(users));
POST Request
const newUser = {
name: 'John Doe',
email: 'john@example.com'
};
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newUser)
})
.then(response => response.json())
.then(result => console.log('Success:', result));
PUT Request
const updatedUser = {
name: 'John Smith',
email: 'johnsmith@example.com'
};
fetch('https://api.example.com/users/123', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updatedUser)
})
.then(response => response.json())
.then(result => console.log('Updated:', result));
DELETE Request
fetch('https://api.example.com/users/123', {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
console.log('User deleted successfully');
}
});
Handling Responses
The fetch response object has several useful properties and methods:
fetch('https://api.example.com/data')
.then(response => {
// Check if request was successful
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// Check response type
const contentType = response.headers.get('content-type');
// Parse based on content type
if (contentType && contentType.includes('application/json')) {
return response.json();
} else {
return response.text();
}
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Common Response Methods
response.json()
- Parse JSON responseresponse.text()
- Get response as textresponse.blob()
- Get response as blob (for files)response.arrayBuffer()
- Get response as array bufferresponse.formData()
- Get response as form data
Error Handling
Fetch only rejects on network errors, not HTTP errors. Here’s how to handle both:
async function fetchWithErrorHandling(url) {
try {
const response = await fetch(url);
// Check if HTTP request was successful
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === 'TypeError') {
console.error('Network error:', error.message);
} else {
console.error('HTTP error:', error.message);
}
throw error;
}
}
Working with Headers
You can set custom headers for your requests:
fetch('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer your-token-here',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
Uploading Files
Use FormData to upload files:
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('name', 'my-file');
fetch('https://api.example.com/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(result => console.log('Upload successful:', result));
Canceling Requests
Use AbortController to cancel ongoing requests:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/slow-data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
}
});
// Cancel the request after 5 seconds
setTimeout(() => controller.abort(), 5000);
Best Practices
- Always check response.ok: Don’t assume success
- Handle errors properly: Catch both network and HTTP errors
- Use async/await: Cleaner than .then() chains
- Set appropriate headers: Especially Content-Type for POST/PUT
- Cancel long-running requests: Use AbortController for user experience
Real-World Example
Here’s a complete example of a user management system:
class UserAPI {
constructor(baseURL) {
this.baseURL = baseURL;
}
async getUsers() {
const response = await fetch(`${this.baseURL}/users`);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
}
async createUser(userData) {
const response = await fetch(`${this.baseURL}/users`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
}
async updateUser(id, userData) {
const response = await fetch(`${this.baseURL}/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
}
async deleteUser(id) {
const response = await fetch(`${this.baseURL}/users/${id}`, {
method: 'DELETE'
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return true;
}
}
// Usage
const userAPI = new UserAPI('https://api.example.com');
// Get all users
userAPI.getUsers()
.then(users => console.log('Users:', users))
.catch(error => console.error('Failed to get users:', error));
// Create a new user
userAPI.createUser({ name: 'Jane Doe', email: 'jane@example.com' })
.then(user => console.log('Created user:', user))
.catch(error => console.error('Failed to create user:', error));
Summary
The Fetch API is a powerful, built-in way to make HTTP requests in JavaScript. It’s promise-based, supports all HTTP methods, and provides excellent error handling. Whether you’re building a simple app or a complex web application, the Fetch API gives you the tools you need to communicate with servers effectively.