Skip to main content

HTTP Requests Guide

Learn how to make HTTP requests from your Invoke functions.

Overview

export default async function handler(req, res) {
const response = await fetch('https://api.example.com/data')
const data = await response.json()
res.json(data)
}

GET Requests

export default async function handler(req, res) {
// Simple GET
const response = await fetch('https://api.github.com/users/octocat')
const user = await response.json()

// GET with query parameters
const params = new URLSearchParams({ q: 'javascript', sort: 'stars', order: 'desc' })
const searchResponse = await fetch(`https://api.github.com/search/repositories?${params}`)
const searchResults = await searchResponse.json()

res.json({ user, searchResults })
}

POST Requests

export default async function handler(req, res) {
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 data = await response.json()
res.status(201).json(data)
}

Headers and Authentication

export default async function handler(req, res) {
// Bearer token
const response = await fetch('https://api.example.com/protected', {
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`,
'Content-Type': 'application/json'
}
})

// API key header
const keyResponse = await fetch('https://api.example.com/data', {
headers: {
'X-API-Key': process.env.API_KEY,
'X-Request-ID': crypto.randomUUID(),
'User-Agent': 'Invoke-Function/1.0'
}
})

res.json({ success: true })
}

PUT / PATCH / DELETE

export default async function handler(req, res) {
const apiUrl = 'https://api.example.com/resource/123'

const putResponse = await fetch(apiUrl, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Updated Name' })
})

const patchResponse = await fetch(apiUrl, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'new@example.com' })
})

const deleteResponse = await fetch(apiUrl, { method: 'DELETE' })

res.json({ put: putResponse.status, patch: patchResponse.status, delete: deleteResponse.status })
}

Response Handling

export default async function handler(req, res) {
const response = await fetch('https://api.example.com/data')
const contentType = response.headers.get('content-type')

if (!response.ok) {
return res.status(response.status).json({ error: `HTTP ${response.status}` })
}

if (contentType?.includes('application/json')) {
const data = await response.json()
res.json(data)
} else if (contentType?.includes('text/')) {
const text = await response.text()
res.send(text)
} else {
const buffer = await response.arrayBuffer()
res.send(Buffer.from(buffer))
}
}

Error Handling

export default async function handler(req, res) {
try {
const response = await fetch('https://api.example.com/data')

if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return res.status(response.status).json({
error: 'API request failed',
status: response.status,
details: errorData
})
}

const data = await response.json()
res.json(data)
} catch (error) {
console.error('Request failed:', error)
res.status(500).json({ error: 'Network error', message: error.message })
}
}

Timeout Handling

export default async function handler(req, res) {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 5000)

try {
const response = await fetch('https://api.example.com/slow', {
signal: controller.signal
})
clearTimeout(timeoutId)
const data = await response.json()
res.json(data)
} catch (error) {
if (error.name === 'AbortError') {
res.status(408).json({ error: 'Request timeout' })
} else {
res.status(500).json({ error: error.message })
}
}
}

Common Patterns

Parallel Requests

export default async function handler(req, res) {
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())
])

res.json({ users, posts, comments })
}

Retry with Exponential Backoff

async function fetchWithRetry(url, options = {}, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options)
if (response.ok) return response
if (response.status >= 500 && i < retries - 1) {
await sleep(1000 * Math.pow(2, i))
continue
}
return response
} catch (error) {
if (i === retries - 1) throw error
await sleep(1000 * Math.pow(2, i))
}
}
}

export default async function handler(req, res) {
const response = await fetchWithRetry('https://api.example.com/data')
const data = await response.json()
res.json(data)
}

Response Caching

export default async function handler(req, res) {
const cacheKey = `api:data:${req.query.id}`

let data = await kv.get(cacheKey)
if (!data) {
const response = await fetch(`https://api.example.com/data/${req.query.id}`)
data = await response.json()
await kv.set(cacheKey, data, 600000) // 10 min TTL
}

res.json(data)
}

Best Practices

1. Use Environment Variables for Secrets

// ❌ DON'T hardcode secrets
const response = await fetch('https://api.example.com', {
headers: { Authorization: 'Bearer hardcoded-token' }
})

// ✅ DO use environment variables
const response = await fetch('https://api.example.com', {
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
})

2. Always Handle Errors

try {
const response = await fetch('https://api.example.com')
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const data = await response.json()
res.json(data)
} catch (error) {
res.status(500).json({ error: error.message })
}

3. Set Timeouts

const controller = new AbortController()
setTimeout(() => controller.abort(), 10000)
const response = await fetch(url, { signal: controller.signal })

Next Steps