Web Fetch API
Make HTTP requests and handle responses with modern JavaScript
🌐 What is the Fetch API?
The Fetch API provides a modern way to make HTTP requests in JavaScript. It's a promise-based alternative to XMLHttpRequest, making it easier to work with APIs and handle responses.
// Simple GET request
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => {
console.log('Users:', data);
})
.catch(error => {
console.error('Error:', error);
});
Output:
Users: [{id: 1, name: "John"}, {id: 2, name: "Jane"}]
Request completed successfully!
HTTP Methods with Fetch
GET Request
Retrieve data from server
fetch('/api/data')
POST Request
Send data to server
fetch('/api/users', {method: 'POST'})
PUT Request
Update existing data
fetch('/api/users/1', {method: 'PUT'})
DELETE Request
Remove data from server
fetch('/api/users/1', {method: 'DELETE'})
🔹 Basic GET Request
Fetching data from an API:
// Simple GET request
async function fetchUsers() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
// Check if request was successful
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
console.log('Users loaded:', users.length);
// Display users
displayUsers(users);
} catch (error) {
console.error('Failed to fetch users:', error);
document.getElementById('error').textContent = 'Failed to load users';
}
}
function displayUsers(users) {
const userList = document.getElementById('user-list');
userList.innerHTML = users.map(user => `
<div class="user-card">
<h3>${user.name}</h3>
<p>Email: ${user.email}</p>
<p>City: ${user.address.city}</p>
</div>
`).join('');
}
// Call the function
fetchUsers();
User List Demo:
🔹 POST Request with Data
Sending data to a server:
// POST request to create new user
async function createUser(userData) {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const newUser = await response.json();
console.log('User created:', newUser);
return newUser;
} catch (error) {
console.error('Failed to create user:', error);
throw error;
}
}
// Example usage
async function handleFormSubmit() {
const formData = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
phone: document.getElementById('phone').value
};
try {
const newUser = await createUser(formData);
alert('User created successfully!');
// Clear form
document.getElementById('user-form').reset();
} catch (error) {
alert('Failed to create user. Please try again.');
}
}
// Form submission
document.getElementById('user-form').addEventListener('submit', function(e) {
e.preventDefault();
handleFormSubmit();
});
Create User Form:
🔹 Handling Different Response Types
Fetch can handle various response formats:
// Handle JSON response
async function fetchJSON(url) {
const response = await fetch(url);
const data = await response.json();
return data;
}
// Handle text response
async function fetchText(url) {
const response = await fetch(url);
const text = await response.text();
return text;
}
// Handle blob (for images, files)
async function fetchImage(url) {
const response = await fetch(url);
const blob = await response.blob();
// Create image URL
const imageUrl = URL.createObjectURL(blob);
// Display image
const img = document.createElement('img');
img.src = imageUrl;
document.body.appendChild(img);
return blob;
}
// Handle form data
async function fetchFormData(url) {
const response = await fetch(url);
const formData = await response.formData();
return formData;
}
// Check response type and handle accordingly
async function smartFetch(url) {
const response = await fetch(url);
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else if (contentType && contentType.includes('text/')) {
return await response.text();
} else {
return await response.blob();
}
}
Response Types:
- .json(): Parse JSON data
- .text(): Get plain text
- .blob(): Binary data (images, files)
- .formData(): Form data
- .arrayBuffer(): Raw binary data
🔹 Request Configuration
Customize requests with headers, authentication, and more:
// Advanced fetch configuration
async function advancedFetch() {
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token-here',
'X-Custom-Header': 'custom-value'
},
body: JSON.stringify({
name: 'John Doe',
email: '[email protected]'
}),
mode: 'cors', // cors, no-cors, same-origin
credentials: 'include', // include, same-origin, omit
cache: 'no-cache', // default, no-cache, reload, force-cache
redirect: 'follow', // manual, follow, error
referrerPolicy: 'no-referrer' // no-referrer, origin, etc.
};
try {
const response = await fetch('https://api.example.com/users', options);
// Check response status
if (response.status === 401) {
throw new Error('Unauthorized - check your token');
}
if (response.status === 404) {
throw new Error('Resource not found');
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
// Timeout wrapper
function fetchWithTimeout(url, options = {}, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Request timeout')), timeout)
)
]);
}
Request Options:
✅ Custom headers for authentication
✅ CORS configuration
✅ Credential handling
✅ Cache control
✅ Timeout handling
🔹 Error Handling Best Practices
Robust error handling for fetch requests:
// Comprehensive error handling
async function robustFetch(url, options = {}) {
try {
// Check if browser supports fetch
if (!window.fetch) {
throw new Error('Fetch API not supported');
}
const response = await fetch(url, options);
// Handle different error scenarios
if (!response.ok) {
// Create detailed error message
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
// Try to get error details from response
try {
const errorData = await response.json();
if (errorData.message) {
errorMessage += ` - ${errorData.message}`;
}
} catch (e) {
// Response is not JSON, use status text
}
throw new Error(errorMessage);
}
return response;
} catch (error) {
// Handle different types of errors
if (error.name === 'TypeError') {
// Network error or CORS issue
throw new Error('Network error - check your connection');
} else if (error.message.includes('timeout')) {
throw new Error('Request timed out - server is slow');
} else {
// Re-throw other errors
throw error;
}
}
}
// Usage with user feedback
async function loadDataWithFeedback() {
const loadingElement = document.getElementById('loading');
const errorElement = document.getElementById('error');
const dataElement = document.getElementById('data');
try {
// Show loading
loadingElement.style.display = 'block';
errorElement.style.display = 'none';
const response = await robustFetch('/api/data');
const data = await response.json();
// Show data
dataElement.innerHTML = JSON.stringify(data, null, 2);
} catch (error) {
// Show error
errorElement.textContent = error.message;
errorElement.style.display = 'block';
} finally {
// Hide loading
loadingElement.style.display = 'none';
}
}