Fetch API
Fetch API cheat sheet with GET/POST requests, headers, error handling, AbortController, streaming, and async/await code examples.
New to Async JavaScript? Start Here First!
This sheet covers the Fetch API for making HTTP requests. If you're new to promises, async/await, or asynchronous JavaScript patterns, we recommend starting with our async JavaScript fundamentals sheet first.
Start with Async JavaScript FundamentalsOther JavaScript Sheets
Sign in to mark items as known and track your progress.
Sign inBasic Requests
Common HTTP request patterns with Fetch API
GET Requests
Fetching data from APIs and handling responses
// Simple GET
const response = await fetch('https://api.example.com/data')
const data = await response.json()
// GET with query parameters
const params = new URLSearchParams({
page: 1,
limit: 10,
sort: 'date'
})
const response = await fetch(\`https://api.example.com/data?\${params}\`)
// GET with headers
const response = await fetch('https://api.example.com/data', {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer token123'
}
})POST Requests
Sending data to create new resources
// POST JSON data
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'John Doe',
email: 'john@example.com'
})
})
// POST FormData (multipart/form-data)
const formData = new FormData()
formData.append('name', 'John Doe')
formData.append('avatar', fileInput.files[0])
const response = await fetch('https://api.example.com/users', {
method: 'POST',
body: formData // No Content-Type header needed!
})
// POST URL encoded form
const params = new URLSearchParams()
params.append('username', 'john')
params.append('password', 'secret')
const response = await fetch('https://api.example.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params
})PUT, PATCH, DELETE
Updating and deleting resources with proper methods
// PUT - Full update
const response = await fetch(\`https://api.example.com/users/\${id}\`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Jane Doe',
email: 'jane@example.com',
age: 30
})
})
// PATCH - Partial update
const response = await fetch(\`https://api.example.com/users/\${id}\`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'newemail@example.com'
})
})
// DELETE
const response = await fetch(\`https://api.example.com/users/\${id}\`, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer token123'
}
})
if (response.ok) {
console.log('Resource deleted')
}Request Configuration
Advanced request options for headers, CORS, caching, and credentials
Headers & Authentication
Working with headers and authentication tokens
// Headers object
const headers = new Headers()
headers.append('Content-Type', 'application/json')
headers.set('Authorization', 'Bearer token123')
headers.get('Content-Type') // 'application/json'
headers.has('Authorization') // true
headers.delete('X-Custom')
// Headers in request
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123',
'X-API-Key': 'secret-key',
'Accept-Language': 'en-US',
'User-Agent': 'MyApp/1.0'
}
})
// Headers from response
const contentType = response.headers.get('content-type')
const lastModified = response.headers.get('last-modified')
const customHeader = response.headers.get('x-custom-header')
// Iterate over headers
for (const [key, value] of response.headers.entries()) {
console.log(\`\${key}: \${value}\`)
}CORS & Request Modes
Handling Cross-Origin Resource Sharing and request modes
// CORS modes
await fetch(url, {
mode: 'cors' // Default - follows CORS protocol
})
await fetch(url, {
mode: 'no-cors' // Limited, opaque response
})
await fetch(url, {
mode: 'same-origin' // Only same-origin requests
})
// Credentials (cookies, auth headers)
await fetch(url, {
credentials: 'include' // Always send
})
await fetch(url, {
credentials: 'same-origin' // Same-origin only (default)
})
await fetch(url, {
credentials: 'omit' // Never send
})
// Handling CORS errors
try {
const response = await fetch('https://api.external.com/data', {
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
})
if (!response.ok) {
throw new Error(\`HTTP error! status: \${response.status}\`)
}
const data = await response.json()
} catch (error) {
if (error instanceof TypeError) {
console.error('CORS error or network failure:', error)
}
}Cache Control
Managing request caching and cache strategies
// Cache modes
await fetch(url, {
cache: 'default' // Browser decides
})
await fetch(url, {
cache: 'no-cache' // Validate with server
})
await fetch(url, {
cache: 'reload' // Bypass cache completely
})
await fetch(url, {
cache: 'force-cache' // Use cache if available
})
await fetch(url, {
cache: 'only-if-cached' // Cache only, fail otherwise
})
// Cache with headers
const response = await fetch(url, {
cache: 'no-cache',
headers: {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
})
// Conditional requests
const response = await fetch(url, {
headers: {
'If-Modified-Since': lastModified,
'If-None-Match': etag
}
})
if (response.status === 304) {
console.log('Not modified, use cached version')
}Response Handling
Processing responses, handling errors, and parsing data
Response Types
Parsing different response formats and handling content types
// JSON response
const response = await fetch('/api/data')
const json = await response.json()
// Text response
const response = await fetch('/api/text')
const text = await response.text()
// Blob (binary data)
const response = await fetch('/api/image')
const blob = await response.blob()
const url = URL.createObjectURL(blob)
// FormData
const response = await fetch('/api/form')
const formData = await response.formData()
// ArrayBuffer
const response = await fetch('/api/binary')
const buffer = await response.arrayBuffer()
// Clone response (read body twice)
const response = await fetch('/api/data')
const clone = response.clone()
const json = await response.json()
const text = await clone.text()Error Handling
Comprehensive error handling and retry strategies
// Basic error handling
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(\`HTTP \${response.status}: \${response.statusText}\`)
}
const data = await response.json()
} catch (error) {
if (error instanceof TypeError) {
console.error('Network error:', error)
} else {
console.error('Request failed:', error)
}
}
// Detailed status handling
const response = await fetch(url)
switch(response.status) {
case 200:
return await response.json()
case 204:
return null
case 400:
throw new Error('Bad request')
case 401:
throw new Error('Unauthorized')
case 404:
throw new Error('Not found')
case 500:
throw new Error('Server error')
default:
throw new Error(\`Unexpected status: \${response.status}\`)
}
// Network timeout
try {
const response = await fetch(url, {
signal: AbortSignal.timeout(5000)
})
return await response.json()
} catch (error) {
if (error.name === 'TimeoutError') {
console.error('Request timed out')
}
}Advanced Features
Request cancellation, interceptors, and advanced patterns
Abort Controller
Cancelling requests and implementing timeouts
// Basic cancellation
const controller = new AbortController()
const request = fetch(url, {
signal: controller.signal
})
// Cancel the request
controller.abort()
// Cancel on user action
const controller = new AbortController()
const fetchButton = document.getElementById('fetch')
const cancelButton = document.getElementById('cancel')
fetchButton.addEventListener('click', async () => {
try {
const response = await fetch(url, {
signal: controller.signal
})
const data = await response.json()
console.log(data)
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was cancelled')
}
}
})
cancelButton.addEventListener('click', () => {
controller.abort()
})Request Interceptors
Creating middleware for requests and responses
// Basic interceptor pattern
const originalFetch = window.fetch
window.fetch = async function(...args) {
console.log('Request:', args)
const response = await originalFetch(...args)
console.log('Response:', response)
return response
}
// Request/Response interceptor class
class FetchInterceptor {
constructor() {
this.requestInterceptors = []
this.responseInterceptors = []
}
addRequestInterceptor(fn) {
this.requestInterceptors.push(fn)
}
addResponseInterceptor(fn) {
this.responseInterceptors.push(fn)
}
async fetch(url, options = {}) {
// Run request interceptors
let modifiedOptions = options
for (const interceptor of this.requestInterceptors) {
modifiedOptions = await interceptor(url, modifiedOptions)
}
let response = await fetch(url, modifiedOptions)
// Run response interceptors
for (const interceptor of this.responseInterceptors) {
response = await interceptor(response)
}
return response
}
}File Operations
Uploading files and handling downloads with progress
// Single file upload
const fileInput = document.getElementById('file')
const file = fileInput.files[0]
const formData = new FormData()
formData.append('file', file)
formData.append('description', 'Profile photo')
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
})
// Multiple files
const formData = new FormData()
for (const file of fileInput.files) {
formData.append('files[]', file)
}
// Download file
async function downloadFile(url, filename) {
const response = await fetch(url)
const blob = await response.blob()
const downloadUrl = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = downloadUrl
a.download = filename
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(downloadUrl)
}