webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
JavaScript · Lesson 15 of 17

fetch, JSON and AbortController

Correct requests, checking res.ok, query params and cancellation.

Updated

What fetch is

fetch is the native function (in the browser, Node and Next) for making HTTP requests: you ask a server for data or send data to it. It returns a Promise with a Response object.

const res = await fetch('/api/posts')
const posts = await res.json()

Two awaits: the first waits for the response headers, the second reads and parses the body.

Trap no. 1: fetch doesn't throw on 404 / 500

fetch throws an error only on network problems (offline, DNS, CORS). A 404 or 500 response is, as far as it's concerned, a valid response.

const res = await fetch('/api/posts')
if (!res.ok) throw new Error(`HTTP ${res.status}`)   // res.ok = status 200–299
const posts = await res.json()

The Response object

Property / method What it gives
res.ok true for 2xx
res.status 200, 404…
res.headers.get('content-type') a header
res.json() the body parsed as JSON (a Promise)
res.text() the body as text
res.blob() a file / image

The body can be read only once.

Kinds of requests

You want to... How
read fetch(url) — GET by default
send JSON method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data)
send a form / file method: 'POST', body: new FormData(form) — without a Content-Type, the browser sets it
update / delete method: 'PATCH' / 'DELETE'
send cookies cross-origin credentials: 'include'
await fetch('/api/posts', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Hello' }),
})

What JSON is

JSON (JavaScript Object Notation) is the text format data travels in between the browser and the server. It looks like a JS object, but it's a string, with strict rules: keys in double quotes, no functions, no undefined, no trailing comma.

JSON.stringify({ a: 1, d: new Date() })  // '{"a":1,"d":"2026-10-08T..."}' — the Date becomes a string
JSON.parse('{"a":1}')                    // { a: 1 } — throws a SyntaxError on invalid JSON

URLs with parameters

const url = new URL('/api/search', location.origin)
url.searchParams.set('q', 'next js')   // automatic encoding: q=next+js
url.searchParams.set('page', '2')
fetch(url)

Don't concatenate by hand — characters like &, ?, a space break the URL.

Cancellation and timeouts with AbortController

An old request that responds after a new one (search-as-you-type) can overwrite the correct result — a race condition. The fix: cancel the old request.

const controller = new AbortController()
fetch(url, { signal: controller.signal })
controller.abort()                                  // the request throws an AbortError

fetch(url, { signal: AbortSignal.timeout(5000) })   // automatic cancellation after 5s

A helper written once

async function api(path, init) {
  const res = await fetch(path, init)
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)
  return res.status === 204 ? null : res.json()
}

fetch in Next.js

In Server Components, fetch runs on the server (API keys stay secret). In Client Components, for server data, prefer TanStack Query over fetch in useEffect.

Summary

  • fetch → Response; check res.ok, then res.json().
  • JSON = text; stringify when sending, parse (or res.json()) when receiving.
  • URL + searchParams for parameters; AbortController for cancellation.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.