Fetch API Guide: Make HTTP Requests in Modern JavaScript
Learn how to use the Fetch API for GET, POST, JSON, headers, errors, cancellation, credentials, and cleaner browser request code.
Fetch is the standard modern way to call HTTP from the browser
The Fetch API lets JavaScript make network requests and receive responses as promises. It is used for loading JSON, submitting forms, calling backend APIs, uploading data, and building interactive interfaces that do not reload the full page for every action.
A basic fetch call returns a response object. That response still needs to be inspected and parsed. For JSON APIs, developers usually call await response.json(). But parsing should happen only after you know how you want to handle status codes and errors.
Important Fetch habits
- Check
response.okbefore treating the request as successful. - Set
Content-Type: application/jsonwhen sending JSON. - Use
AbortControllerto cancel requests that are no longer relevant. - Handle credentials intentionally when cookies or sessions are involved.
- Use a small wrapper when the app needs consistent error behavior.
HTTP errors are not network errors
Fetch rejects the promise for network failures, aborted requests, and similar low-level failures. It does not reject just because the server returns 400, 404, or 500. That surprises many developers. Your code must decide how to handle unsuccessful HTTP responses.
This distinction matters in user interfaces. A 401 may mean the user needs to sign in again. A 422 may show form validation errors. A 500 may show a retry message and log diagnostic detail. Treating all failures the same creates poor user experience and weak debugging information.
Create a small request layer
Production apps usually benefit from a thin wrapper around Fetch. The wrapper can add a base URL, default headers, JSON parsing, timeout behavior, credential handling, and consistent error objects. It should stay small enough that developers still understand the actual HTTP request.
Fetch is simple, but production request handling still needs care: timeouts, retries where appropriate, request cancellation, loading states, and useful error messages. A clean Fetch wrapper keeps those rules consistent across the frontend.
Handle retries carefully
Not every failed request should be retried. Retrying a safe GET may be fine. Retrying a payment, form submission, or destructive action can create duplicate side effects unless the server supports idempotency. Frontend retry logic should understand the kind of action being performed.
For user interfaces, show enough feedback that people do not click repeatedly because nothing appears to happen. Network code and UI state belong together: disabled buttons, progress indicators, retry options, and clear messages make HTTP behavior understandable to users.
Also consider accessibility. Loading text, disabled states, and error messages should be visible to assistive technology, not only represented by color or animation. Good Fetch handling supports both technical reliability and usable interface feedback.
Finally, test slow networks. Many request bugs appear only when latency exposes double clicks, stale responses, or missing cancellation logic.