Fetch JSON in JavaScript

Last updated:

To fetch JSON in JavaScript, call fetch(url) and then await response.json() — the second call reads the response body stream and parses it as JSON. The global fetch() is built into all modern browsers and Node.js 18+ with no installation; Node.js 16 and earlier need node-fetch. One critical detail: fetch() only rejects on network-level failures (DNS errors, no connection, CORS). A 404 or 500 response resolves successfully, so always check response.ok (true for 2xx status codes) before calling response.json(), or you risk parsing an error body as valid data. This guide covers GET and POST patterns with async/await and .then(), checking response.ok, setting Content-Type: application/json, and Node.js 18+ fetch usage.

Format and inspect your fetch() JSON responses

Paste any JSON payload to validate, pretty-print, and explore it instantly — no account required.

Open JSON Formatter

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.

Frequently asked questions

How do I fetch JSON from an API in JavaScript?

Use fetch(url), check response.ok, then callawait response.json() to parse the body. Wrap in async/awaitand try/catch for error handling.

What is the difference between response.json() and JSON.parse?

response.json() reads the fetch response body stream and parses it, returning a Promise. JSON.parse is synchronous and takes a string already in memory. Useresponse.json() for fetch responses.

How do I POST JSON with fetch()?

Set method: 'POST', add Content-Type: application/json to headers, and set body: JSON.stringify(yourObject). Checkresponse.ok before parsing the response.

How do I set Content-Type for JSON in fetch?

Pass headers: { 'Content-Type': 'application/json' } in the fetch options. This header is only required on requests with a body (POST, PUT, PATCH).

How do I handle fetch errors?

Catch network errors with try/catch. Check response.ok for HTTP errors (4xx, 5xx) — fetch does not reject for non-2xx responses. Both error types need separate handling.

Does fetch work in Node.js?

Yes. fetch() is built into Node.js 18+. For older versions, installnode-fetch. Next.js also exposes fetch in all server-side code with additional caching options.