Docs
README
11.3 Fetch API and HTTP
Overview
The Fetch API provides a modern, Promise-based way to make HTTP requests in JavaScript. It's the successor to XMLHttpRequest (XHR) and offers a cleaner, more powerful interface.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Fetch API Flow β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β JavaScript Network Server β
β βββββββββββ βββββββββ βββββββββββ β
β β βββfetch()βββΆβ βββRequestβββΆβ β β
β β Code β β HTTP β β API β β
β β βββPromiseβββ βββResponseββ β β
β βββββββββββ βββββββββ βββββββββββ β
β β
β fetch(url, options) β
β β β
β βΌ β
β βββββββββββββββββββ β
β β Promise β β
β β βββββββββββββ β β
β β β Response β β β Headers, Status, Body β
β β βββββββββββββ β β
β βββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HTTP Methods
| Method | Purpose | Has Body | Idempotent |
|---|---|---|---|
| GET | Retrieve data | No | Yes |
| POST | Create resource | Yes | No |
| PUT | Replace resource | Yes | Yes |
| PATCH | Partial update | Yes | No |
| DELETE | Remove resource | Optional | Yes |
| HEAD | Get headers only | No | Yes |
| OPTIONS | Check capabilities | No | Yes |
Basic Fetch Syntax
// GET request (default)
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
// With async/await
async function getData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error);
}
}
Fetch Options
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Fetch Request Options β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β fetch(url, { β
β method: 'POST', // HTTP method β
β headers: { // Request headers β
β 'Content-Type': 'application/json', β
β 'Authorization': 'Bearer token123' β
β }, β
β body: JSON.stringify(data), // Request body β
β mode: 'cors', // cors, no-cors, same-origin β
β credentials: 'include', // include, same-origin, omit β
β cache: 'no-cache', // Cache mode β
β redirect: 'follow', // follow, error, manual β
β signal: controller.signal // AbortController signal β
β }) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Response Object
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Response Object β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β response.ok β Boolean: true if status 200-299 β
β response.status β HTTP status code (200, 404, etc.) β
β response.statusText β Status message ("OK", "Not Found") β
β response.headers β Headers object β
β response.url β Final URL after redirects β
β response.type β basic, cors, error, opaque β
β response.redirected β Whether response is redirected β
β β β
β Body Methods (return Promises): β
β ββββββββββββββββββββββββββββββ β
β response.json() β Parse as JSON β
β response.text() β Parse as text string β
β response.blob() β Parse as binary Blob β
β response.arrayBuffer()β Parse as ArrayBuffer β
β response.formData() β Parse as FormData β
β β
β β οΈ Body can only be read ONCE! β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Common Content Types
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Content-Type Headers β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β application/json β JSON data β
β application/x-www-form-urlencoded β Form data (default) β
β multipart/form-data β File uploads β
β text/plain β Plain text β
β text/html β HTML content β
β application/octet-stream β Binary data β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Error Handling
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Fetch Error Handling β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β β οΈ IMPORTANT: Fetch only rejects on network errors! β
β β
β HTTP 404 or 500 β Promise RESOLVES (response.ok = false) β
β Network failure β Promise REJECTS β
β β
β Correct Error Handling: β
β ββββββββββββββββββββββ β
β async function fetchWithErrorHandling(url) { β
β const response = await fetch(url); β
β β
β if (!response.ok) { β
β throw new Error(`HTTP ${response.status}`); β
β } β
β β
β return response.json(); β
β } β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Request/Response Headers
// Creating headers
const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Bearer token');
// Or as object
const headers2 = new Headers({
'Content-Type': 'application/json',
});
// Headers methods
headers.get('Content-Type'); // Get value
headers.has('Authorization'); // Check existence
headers.set('X-Custom', 'value'); // Set value
headers.delete('X-Custom'); // Delete header
headers.entries(); // Iterator
AbortController - Canceling Requests
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Request Cancellation β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β const controller = new AbortController(); β
β const { signal } = controller; β
β β
β fetch(url, { signal }) β
β .then(response => response.json()) β
β .catch(err => { β
β if (err.name === 'AbortError') { β
β console.log('Request cancelled'); β
β } β
β }); β
β β
β // Later, to cancel: β
β controller.abort(); β
β β
β // With timeout: β
β const timeoutId = setTimeout(() => controller.abort(), 5000); β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Common Request Patterns
GET with Query Parameters
const params = new URLSearchParams({
page: 1,
limit: 10,
search: 'javascript',
});
fetch(`https://api.example.com/items?${params}`).then((response) =>
response.json()
);
POST with JSON
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'John',
email: 'john@example.com',
}),
});
File Upload
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('description', 'My file');
fetch('https://api.example.com/upload', {
method: 'POST',
body: formData,
// Don't set Content-Type - browser sets it with boundary
});
CORS (Cross-Origin Resource Sharing)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CORS Overview β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Same-Origin: scheme + host + port must match β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β http://example.com/page1 β
β http://example.com/page2 β Same origin β β
β https://example.com/page1 β Different scheme β β
β http://api.example.com β Different host β β
β http://example.com:8080 β Different port β β
β β
β CORS Headers (Server Response): β
β ββββββββββββββββββββββββββββββ β
β Access-Control-Allow-Origin: * β
β Access-Control-Allow-Methods: GET, POST, PUT β
β Access-Control-Allow-Headers: Content-Type, Authorization β
β Access-Control-Allow-Credentials: true β
β β
β Preflight Request (OPTIONS): β
β ββββββββββββββββββββββββββββ β
β Sent automatically for: β
β β’ Non-simple methods (PUT, DELETE, PATCH) β
β β’ Custom headers β
β β’ Content-Type other than form-urlencoded, multipart, text β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Credentials and Cookies
// Include cookies in same-origin requests
fetch(url, { credentials: 'same-origin' });
// Include cookies in cross-origin requests
fetch(url, { credentials: 'include' });
// Never include cookies
fetch(url, { credentials: 'omit' });
Retry Logic
async function fetchWithRetry(url, options = {}, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise((r) => setTimeout(r, delay * Math.pow(2, i)));
}
}
}
Streaming Responses
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Response Streaming β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β async function* streamResponse(response) { β
β const reader = response.body.getReader(); β
β const decoder = new TextDecoder(); β
β β
β while (true) { β
β const { done, value } = await reader.read(); β
β if (done) break; β
β yield decoder.decode(value, { stream: true }); β
β } β
β } β
β β
β // Usage β
β const response = await fetch(url); β
β for await (const chunk of streamResponse(response)) { β
β console.log('Received:', chunk); β
β } β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Best Practices
- β’Always check response.ok - HTTP errors don't reject the Promise
- β’Use AbortController for timeout and cancellation
- β’Handle errors properly - network failures and HTTP errors
- β’Set appropriate Content-Type - especially for POST/PUT
- β’Use async/await for cleaner code
- β’Consider retry logic for unreliable networks
- β’Don't forget CORS when dealing with external APIs
Common Gotchas
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Common Mistakes β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β β fetch(url).then(data => ...) β
β β fetch(url).then(res => res.json()).then(data => ...) β
β (Response is not the data itself!) β
β β
β β Assuming 404 will throw an error β
β β Check response.ok before processing β
β β
β β Reading body twice β
β β Clone response if you need to read it multiple times β
β const clone = response.clone(); β
β β
β β Setting Content-Type for FormData β
β β Let browser set it (includes boundary for multipart) β
β β
β β Forgetting await with async functions β
β β Always await fetch and body methods β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Browser Support
The Fetch API is supported in all modern browsers. For older browsers, use a polyfill like whatwg-fetch or node-fetch for Node.js environments.
Key Takeaways
- β’Fetch is Promise-based and supports async/await
- β’Check
response.okfor HTTP errors - β’Body methods return Promises and can only be called once
- β’Use AbortController for request cancellation
- β’CORS restrictions apply to cross-origin requests
- β’Proper error handling requires checking both network and HTTP errors