> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Chalarangelo/30-seconds-of-code/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP Requests in JavaScript

> Learn how to make HTTP requests using the Fetch API and handle responses

# HTTP Requests with Fetch API

The Fetch API is the modern way to send asynchronous HTTP requests in JavaScript. It provides a powerful and flexible feature set for making requests and handling responses.

## Basic Fetch Request

```javascript theme={null}
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
```

## Using async/await

The more modern and readable approach:

```javascript theme={null}
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error:', error);
  }
}
```

## Aborting Fetch Requests

Aborting a fetch request in JavaScript is a common need. The `signal` option allows you to cancel requests at any time.

### Using AbortController

To create a valid value for the `signal` option, you can use `AbortController.signal` after creating a new instance of `AbortController`. Then, you can use `AbortController.abort()` to cancel the request at any time.

```javascript theme={null}
// Create the AbortController
const controller = new AbortController();
const { signal } = controller;

// Perform the request
fetch('https://my.site.com/data', { signal })
  .then(res => console.log(res))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('Request aborted');
    } else {
      console.error('Error:', err);
    }
  });

// Abort the request
controller.abort();
```

<Tip>
  This is particularly useful in scenarios where a request takes too long or the response is no longer needed, such as when a user navigates away from a page.
</Tip>

### Timeout Pattern

Combine AbortController with a timeout:

```javascript theme={null}
const fetchWithTimeout = (url, timeout = 5000) => {
  const controller = new AbortController();
  const { signal } = controller;

  const timeoutId = setTimeout(() => controller.abort(), timeout);

  return fetch(url, { signal })
    .then(response => {
      clearTimeout(timeoutId);
      return response;
    })
    .catch(error => {
      clearTimeout(timeoutId);
      throw error;
    });
};

// Usage
fetchWithTimeout('https://api.example.com/data', 3000)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Request failed or timed out:', error));
```

## Request Options

### GET Request

```javascript theme={null}
const response = await fetch('https://api.example.com/users');
const users = await response.json();
```

### POST Request

```javascript theme={null}
const response = await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Alice',
    email: 'alice@example.com'
  })
});
const newUser = await response.json();
```

### PUT Request

```javascript theme={null}
const response = await fetch('https://api.example.com/users/123', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Alice Updated',
    email: 'alice.new@example.com'
  })
});
const updatedUser = await response.json();
```

### DELETE Request

```javascript theme={null}
const response = await fetch('https://api.example.com/users/123', {
  method: 'DELETE'
});

if (response.ok) {
  console.log('User deleted successfully');
}
```

## Handling Responses

### Check Response Status

```javascript theme={null}
const response = await fetch('https://api.example.com/data');

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

const data = await response.json();
```

### Different Response Types

```javascript theme={null}
// JSON
const jsonData = await response.json();

// Text
const textData = await response.text();

// Blob (for files)
const blobData = await response.blob();

// ArrayBuffer
const bufferData = await response.arrayBuffer();

// FormData
const formData = await response.formData();
```

## Error Handling

### Comprehensive Error Handling

```javascript theme={null}
async function fetchData(url) {
  try {
    const response = await fetch(url);

    // Check if response is ok (status 200-299)
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    // Network error or abort error
    if (error.name === 'AbortError') {
      console.log('Request was aborted');
    } else if (error instanceof TypeError) {
      console.error('Network error:', error);
    } else {
      console.error('Error:', error.message);
    }
    throw error;
  }
}
```

## Advanced Patterns

### Retry Logic

```javascript theme={null}
const fetchWithRetry = async (url, options = {}, retries = 3) => {
  try {
    return await fetch(url, options);
  } catch (error) {
    if (retries === 0) throw error;
    console.log(`Retrying... (${retries} attempts left)`);
    await new Promise(resolve => setTimeout(resolve, 1000));
    return fetchWithRetry(url, options, retries - 1);
  }
};

// Usage
fetchWithRetry('https://api.example.com/data', {}, 3)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Failed after retries:', error));
```

### Caching Responses

```javascript theme={null}
const cache = new Map();

const fetchWithCache = async (url, ttl = 60000) => {
  const cached = cache.get(url);
  
  if (cached && Date.now() - cached.timestamp < ttl) {
    return cached.data;
  }

  const response = await fetch(url);
  const data = await response.json();

  cache.set(url, {
    data,
    timestamp: Date.now()
  });

  return data;
};

// Usage
const data = await fetchWithCache('https://api.example.com/data', 30000);
```

### Parallel Requests

```javascript theme={null}
const [users, posts, comments] = await Promise.all([
  fetch('https://api.example.com/users').then(r => r.json()),
  fetch('https://api.example.com/posts').then(r => r.json()),
  fetch('https://api.example.com/comments').then(r => r.json())
]);
```

### Sequential Requests

```javascript theme={null}
const fetchSequentially = async (urls) => {
  const results = [];
  
  for (const url of urls) {
    const response = await fetch(url);
    const data = await response.json();
    results.push(data);
  }
  
  return results;
};

// Usage
const urls = [
  'https://api.example.com/users',
  'https://api.example.com/posts',
  'https://api.example.com/comments'
];
const results = await fetchSequentially(urls);
```

## Best Practices

<AccordionGroup>
  <Accordion title="Always handle errors">
    Network requests can fail for many reasons. Always use try/catch or .catch() to handle errors gracefully.
  </Accordion>

  <Accordion title="Check response.ok">
    The fetch API doesn't reject on HTTP errors (like 404 or 500). Always check `response.ok` before processing the response.
  </Accordion>

  <Accordion title="Use AbortController for cleanup">
    In React components or when navigation occurs, use AbortController to cancel pending requests and prevent memory leaks.
  </Accordion>

  <Accordion title="Set appropriate timeouts">
    Don't let requests hang indefinitely. Implement timeout logic to improve user experience.
  </Accordion>

  <Accordion title="Consider caching">
    For frequently accessed data that doesn't change often, implement caching to reduce network requests.
  </Accordion>
</AccordionGroup>
