Fetch API for HTTP requests and AJAX communication

Alex Chang Feb 2026
1 tab
// Basic GET request
fetch('https://api.example.com/users')
  .then(response => {
    console.log('Status:', response.status);
    console.log('OK:', response.ok);
    return response.json();
  })
  .then(data => {
    console.log('Data:', data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

// Async/await syntax (cleaner)
async function fetchUsers() {
  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('Users:', data);
    return data;
  } catch (error) {
    console.error('Fetch error:', error.message);
    throw error;
  }
}

// POST request with JSON
async function createUser(userData) {
  try {
    const response = await fetch('https://api.example.com/users', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token123'
      },
      body: JSON.stringify(userData)
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.message || 'Failed to create user');
    }

    const data = await response.json();
    console.log('Created:', data);
    return data;
  } catch (error) {
    console.error('Error creating user:', error);
    throw error;
  }
}

// Usage
createUser({ name: 'Alice', email: 'alice@example.com' });

// PUT request (update)
async function updateUser(userId, updates) {
  const response = await fetch(`https://api.example.com/users/${userId}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(updates)
  });

  return await response.json();
}

// PATCH request (partial update)
async function patchUser(userId, updates) {
  const response = await fetch(`https://api.example.com/users/${userId}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(updates)
  });

  return await response.json();
}

// DELETE request
async function deleteUser(userId) {
  const response = await fetch(`https://api.example.com/users/${userId}`, {
    method: 'DELETE'
  });

  if (!response.ok) {
    throw new Error('Failed to delete user');
  }

  return response.status === 204 ? null : await response.json();
}

// Handling different response types
async function handleResponse(url) {
  const response = await fetch(url);

  const contentType = response.headers.get('content-type');

  if (contentType?.includes('application/json')) {
    return await response.json();
  } else if (contentType?.includes('text')) {
    return await response.text();
  } else if (contentType?.includes('blob')) {
    return await response.blob();
  }

  return response;
}

// Fetch with timeout
async function fetchWithTimeout(url, timeout = 5000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, {
      signal: controller.signal
    });
    clearTimeout(timeoutId);
    return await response.json();
  } catch (error) {
    if (error.name === 'AbortError') {
      throw new Error('Request timeout');
    }
    throw error;
  }
}

// AbortController for cancellation
const controller = new AbortController();

fetch('https://api.example.com/large-data', {
  signal: controller.signal
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Request cancelled');
    }
  });

// Cancel the request
controller.abort();

// Retry logic
async function fetchWithRetry(url, options = {}, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url, options);

      if (!response.ok && i < retries - 1) {
        throw new Error(`HTTP ${response.status}`);
      }

      return response;
    } catch (error) {
      if (i === retries - 1) throw error;

      const delay = Math.min(1000 * Math.pow(2, i), 10000);
      console.log(`Retry ${i + 1} after ${delay}ms`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Uploading files
async function uploadFile(file) {
  const formData = new FormData();
  formData.append('file', file);
  formData.append('name', file.name);

  const response = await fetch('https://api.example.com/upload', {
    method: 'POST',
    body: formData // No Content-Type header needed
  });

  return await response.json();
}

// Usage with file input
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (file) {
    await uploadFile(file);
  }
});

// Downloading files
async function downloadFile(url, filename) {
  const response = await fetch(url);
  const blob = await response.blob();

  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = filename;
  link.click();

  URL.revokeObjectURL(link.href);
}

// Progress tracking (with readable streams)
async function fetchWithProgress(url, onProgress) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  const contentLength = +response.headers.get('Content-Length');

  let receivedLength = 0;
  const chunks = [];

  while (true) {
    const { done, value } = await reader.read();

    if (done) break;

    chunks.push(value);
    receivedLength += value.length;

    if (onProgress) {
      onProgress(receivedLength / contentLength * 100);
    }
  }

  const blob = new Blob(chunks);
  return blob;
}

// Usage
fetchWithProgress('https://example.com/large-file.zip', (progress) => {
  console.log(`Downloaded: ${progress.toFixed(2)}%`);
});

// Parallel requests
async function fetchMultiple(urls) {
  const promises = urls.map(url => fetch(url).then(r => r.json()));
  return await Promise.all(promises);
}

const urls = [
  'https://api.example.com/users',
  'https://api.example.com/posts',
  'https://api.example.com/comments'
];

const [users, posts, comments] = await fetchMultiple(urls);

// Request/response interceptors pattern
class ApiClient {
  constructor(baseURL) {
    this.baseURL = baseURL;
    this.headers = {
      'Content-Type': 'application/json'
    };
  }

  async request(endpoint, options = {}) {
    const url = `${this.baseURL}${endpoint}`;

    const config = {
      ...options,
      headers: {
        ...this.headers,
        ...options.headers
      }
    };

    try {
      const response = await fetch(url, config);

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      return await response.json();
    } catch (error) {
      console.error('API request failed:', error);
      throw error;
    }
  }

  get(endpoint) {
    return this.request(endpoint);
  }

  post(endpoint, data) {
    return this.request(endpoint, {
      method: 'POST',
      body: JSON.stringify(data)
    });
  }

  put(endpoint, data) {
    return this.request(endpoint, {
      method: 'PUT',
      body: JSON.stringify(data)
    });
  }

  delete(endpoint) {
    return this.request(endpoint, { method: 'DELETE' });
  }

  setAuthToken(token) {
    this.headers['Authorization'] = `Bearer ${token}`;
  }
}

// Usage
const api = new ApiClient('https://api.example.com');
api.setAuthToken('your-token-here');

const users2 = await api.get('/users');
const newUser = await api.post('/users', { name: 'Alice' });

// Handling CORS
fetch('https://api.example.com/data', {
  mode: 'cors', // default
  credentials: 'include' // send cookies
});

// Checking response headers
async function checkHeaders(url) {
  const response = await fetch(url);

  console.log('Content-Type:', response.headers.get('content-type'));
  console.log('Date:', response.headers.get('date'));

  // Iterate all headers
  for (const [key, value] of response.headers.entries()) {
    console.log(`${key}: ${value}`);
  }
}
1 file · javascript Explain with highlit

The Fetch API provides modern interface for HTTP requests returning promises. I use fetch(url) to make GET requests that resolve with Response objects. The response.json() parses JSON data asynchronously. POST requests need method, headers, and body options. Using headers: { 'Content-Type': 'application/json' } sends JSON data. The response.ok checks if status is 200-299 range. I handle network errors with .catch() and HTTP errors by checking response status. The AbortController cancels requests with timeout or user action. CORS errors occur when server doesn't allow cross-origin requests. Understanding request/response lifecycle is crucial for API integration. Fetch is promise-based, cleaner than legacy XMLHttpRequest.