Fetch JSON in JavaScript

The fetch() API is the modern way to make HTTP requests in JavaScript. It returns a Promise, works in all modern browsers and Node.js 18+, and makes consuming JSON APIs straightforward with the .json() response method.

Basic GET request

The minimal pattern to fetch JSON from an API endpoint:

fetch('https://api.example.com/users')
  .then(response => response.json())
  .then(data => {
    console.log(data)
  })

response.json() reads the response body and parses it as JSON. It also returns a Promise, so you need a second .then().

Using async/await (recommended)

The async/await pattern is cleaner and easier to read:

async function getUsers() {
  const response = await fetch('https://api.example.com/users')
  const data = await response.json()
  return data
}

const users = await getUsers()
console.log(users)

Error handling

fetch() only rejects for network failures. A 404 or 500 response does not throw — you must check response.ok:

async function fetchJson(url) {
  const response = await fetch(url)

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

  return response.json()
}

// Usage
try {
  const data = await fetchJson('https://api.example.com/users/1')
  console.log(data)
} catch (error) {
  console.error('Failed:', error.message)
}

POST JSON data

To send JSON in a POST request, set the Content-Type header and stringify the body:

async function createUser(user) {
  const response = await fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(user),
  })

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

  return response.json()
}

const newUser = await createUser({ name: 'Alice', email: 'alice@example.com' })

Request headers

Pass custom headers in the options object. Common headers for JSON APIs:

const response = await fetch('https://api.example.com/data', {
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer your-token-here',
    'Content-Type': 'application/json',
  }
})

Query parameters

Use URLSearchParams to build query strings safely:

const params = new URLSearchParams({
  q: 'javascript',
  page: '1',
  limit: '20',
})

const response = await fetch(`https://api.example.com/search?${params}`)
const data = await response.json()

// URL becomes: https://api.example.com/search?q=javascript&page=1&limit=20

Timeouts

fetch() has no built-in timeout. Use AbortController:

async function fetchWithTimeout(url, timeoutMs = 5000) {
  const controller = new AbortController()
  const timer = setTimeout(() => controller.abort(), timeoutMs)

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

Node.js

fetch() is available natively in Node.js 18+. In earlier versions, use the node-fetch package:

// Node.js 18+ — no import needed
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// Node.js < 18 — install: npm install node-fetch
import fetch from 'node-fetch'
const response = await fetch('https://api.example.com/data')
const data = await response.json()

Common mistakes

  • Not awaiting response.json(): It returns a Promise. You must await it or chain .then().
  • Assuming non-2xx means rejection: fetch() resolves for any completed response, including 404 and 500. Check response.ok.
  • Forgetting Content-Type on POST: Without Content-Type: application/json, many servers reject the body.
  • Reading the body twice: The response body can only be read once. Calling .json() after .text() throws an error.

Validate fetched JSON

If you are unsure whether an API response matches the expected structure, paste it into the JSON Formatter to validate and explore it. For schema validation, use the JSON Schema Validator.